cipher_bureau 0.2.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.
Files changed (57) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.md +160 -0
  3. data/Rakefile +38 -0
  4. data/db/seeds/norwegian/wordloader.rb +47 -0
  5. data/lib/cipher_bureau.rb +59 -0
  6. data/lib/cipher_bureau/data_loader.rb +65 -0
  7. data/lib/cipher_bureau/dictionary.rb +63 -0
  8. data/lib/cipher_bureau/exceptions.rb +25 -0
  9. data/lib/cipher_bureau/password.rb +114 -0
  10. data/lib/cipher_bureau/password_meter.rb +183 -0
  11. data/lib/cipher_bureau/statistic.rb +48 -0
  12. data/lib/cipher_bureau/version.rb +3 -0
  13. data/lib/generators/cipher_bureau/create_migration_generator.rb +40 -0
  14. data/lib/generators/cipher_bureau/load_data_generator.rb +36 -0
  15. data/lib/generators/templates/create_cipher_bureau_dictionaries.rb +41 -0
  16. data/lib/generators/templates/create_cipher_bureau_statistics.rb +39 -0
  17. data/lib/tasks/cipher_bureau_tasks.rake +40 -0
  18. data/test/dummy/README.rdoc +261 -0
  19. data/test/dummy/Rakefile +7 -0
  20. data/test/dummy/app/assets/javascripts/application.js +15 -0
  21. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  22. data/test/dummy/app/controllers/application_controller.rb +3 -0
  23. data/test/dummy/app/helpers/application_helper.rb +2 -0
  24. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  25. data/test/dummy/config.ru +4 -0
  26. data/test/dummy/config/application.rb +59 -0
  27. data/test/dummy/config/boot.rb +10 -0
  28. data/test/dummy/config/database.yml +25 -0
  29. data/test/dummy/config/environment.rb +5 -0
  30. data/test/dummy/config/environments/development.rb +37 -0
  31. data/test/dummy/config/environments/production.rb +67 -0
  32. data/test/dummy/config/environments/test.rb +37 -0
  33. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  34. data/test/dummy/config/initializers/inflections.rb +15 -0
  35. data/test/dummy/config/initializers/mime_types.rb +5 -0
  36. data/test/dummy/config/initializers/secret_token.rb +7 -0
  37. data/test/dummy/config/initializers/session_store.rb +8 -0
  38. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  39. data/test/dummy/config/locales/en.yml +5 -0
  40. data/test/dummy/config/routes.rb +58 -0
  41. data/test/dummy/db/migrate/201301290819401_create_cipher_bureau_dictionaries.rb +19 -0
  42. data/test/dummy/db/migrate/201301290819402_create_cipher_bureau_statistics.rb +17 -0
  43. data/test/dummy/db/schema.rb +46 -0
  44. data/test/dummy/public/404.html +26 -0
  45. data/test/dummy/public/422.html +26 -0
  46. data/test/dummy/public/500.html +25 -0
  47. data/test/dummy/public/favicon.ico +0 -0
  48. data/test/dummy/script/rails +6 -0
  49. data/test/fixtures/cipher_bureau_dictionaries.yml +704 -0
  50. data/test/fixtures/cipher_bureau_statistics.yml +40 -0
  51. data/test/test_helper.rb +15 -0
  52. data/test/units/cipher_bureau/dictionary_test.rb +74 -0
  53. data/test/units/cipher_bureau/password_meter_test.rb +128 -0
  54. data/test/units/cipher_bureau/password_test.rb +188 -0
  55. data/test/units/cipher_bureau/statistic_test.rb +78 -0
  56. data/test/units/cipher_bureau_test.rb +45 -0
  57. metadata +197 -0
@@ -0,0 +1,25 @@
1
+ # Copyright (c) 2013 Dynamic Project Management AS
2
+ # Copyright (c) 2013 Knut I. Stenmark
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ module CipherBureau
24
+ class ArgumentError < StandardError; end
25
+ end
@@ -0,0 +1,114 @@
1
+ # Copyright (c) 2013 Dynamic Project Management AS
2
+ # Copyright (c) 2013 Knut I. Stenmark
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ class CipherBureau::Password
24
+ attr_reader :length, :options
25
+
26
+ class << self
27
+ def random(*args)
28
+ enum :random, *args
29
+ end
30
+
31
+ def letters_and_numbers(*args)
32
+ enum :letters_and_numbers, *args
33
+ end
34
+
35
+ def numbers_only(*args)
36
+ enum :numbers_only, *args
37
+ end
38
+
39
+ def symbols_and_numbers(*args)
40
+ enum :symbols_and_numbers, *args
41
+ end
42
+
43
+ def memorable(*args)
44
+ enum :memorable, *args
45
+ end
46
+
47
+ def strength(password)
48
+ CipherBureau::PasswordMeter.strength(password)
49
+ end
50
+
51
+ private
52
+ def enum(method, *args)
53
+ options = args.extract_options!
54
+ count = args.first || 1
55
+ as_hash = options.delete(:as) == :hash
56
+ if options.delete(:strength)
57
+ res = count.times.collect do
58
+ s = strength( p = self.new(options).send(method) )
59
+ as_hash ? {:password => p, :strength => s } : [p, s]
60
+ end
61
+ else
62
+ res = count.times.collect { self.new(options).send(method) }
63
+ end
64
+ count == 1 ? res.first : res
65
+ end
66
+ end
67
+
68
+ def initialize(options = {})
69
+ @options = options.reverse_merge(CipherBureau.default_memorable_options)
70
+ @options.assert_valid_keys(:length, :country_code, :ascii, :grammar, :name_type, :camelize, :middle_numbers)
71
+ @length = @options.delete(:length) || CipherBureau.password_length
72
+ raise ArgumentError, 'Password length is undefined.' unless @length
73
+ @options.delete(:name_type) unless @options[:grammar] == 'name'
74
+ end
75
+
76
+ NUMBERS = ('0'..'9').to_a
77
+ RANDOM = ('!'..'~').to_a
78
+ LETTERS_AND_NUMBERS = ('a'..'z').to_a + ('A'..'Z').to_a + NUMBERS
79
+ SYMBOLS_AND_NUMBERS = RANDOM - ('a'..'z').to_a - ('A'..'Z').to_a
80
+
81
+ def random(size = length)
82
+ (0...size).map{RANDOM.sample}.join
83
+ end
84
+
85
+
86
+ def letters_and_numbers(size = length)
87
+ (0...size).map{LETTERS_AND_NUMBERS.sample}.join
88
+ end
89
+
90
+ def numbers_only(size = length)
91
+ (0...size).map{NUMBERS.sample}.join
92
+ end
93
+
94
+ def memorable()
95
+ sym_size = length / 4
96
+ end_size = (length - sym_size) / 2
97
+ beg_size = length - end_size - sym_size
98
+ # puts "beg_size: #{beg_size} sym_size: #{sym_size} end_size: #{end_size}"
99
+ beg_word = CipherBureau::Dictionary.random(beg_size, scope)
100
+ end_word = CipherBureau::Dictionary.random(end_size, scope)
101
+ sym_word = options[:middle_numbers] ? numbers_only(sym_size) : symbols_and_numbers(sym_size)
102
+ "#{beg_word}#{sym_word}#{end_word}"
103
+ end
104
+
105
+ def symbols_and_numbers(size = length)
106
+ (0...size).map{SYMBOLS_AND_NUMBERS.sample}.join
107
+ end
108
+
109
+ protected
110
+ def scope
111
+ options.slice(:length, :country_code, :ascii, :grammar, :name_type, :camelize)
112
+ end
113
+
114
+ end
@@ -0,0 +1,183 @@
1
+ # Copyright (c) 2013 Dynamic Project Management AS
2
+ # Copyright (c) 2013 Knut I. Stenmark
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ class CipherBureau::PasswordMeter
24
+ LETTERS = ('a'..'z').to_a.join
25
+ NUMBERS = (0..9).to_a.join
26
+ SYMBOLS = ')!@#$%^&*()'
27
+
28
+ attr_reader :password, :length
29
+ def initialize(password)
30
+ self.password = password
31
+ end
32
+
33
+ def password=(password)
34
+ @absolute_score = nil
35
+ @length = password.length
36
+ @password = password
37
+ end
38
+
39
+ def self.strength(password)
40
+ new(password).strength
41
+ end
42
+
43
+ def strength
44
+ n = absolute_score
45
+ n > 100 ? 100 : (n < 0 ? 0 : n )
46
+ end
47
+
48
+ def verbose_strength
49
+ case strength
50
+ when 0...20 then "Very Weak"
51
+ when 20...40 then "Weak"
52
+ when 40...60 then "Good"
53
+ when 60...80 then "Strong"
54
+ else
55
+ "Very Strong"
56
+ end
57
+ end
58
+
59
+ def absolute_score
60
+ #@absolute_score ||=
61
+ additions - deductions
62
+ end
63
+
64
+ def additions
65
+ number_of_characters + uppercase_letters + lowercase_letters + numbers + symbols + middle_numbers_or_symbols + requirements
66
+ end
67
+
68
+ def deductions
69
+ letters_only + numbers_only + repeated_characters +
70
+ sequential_letters + sequential_numbers + sequential_symbols +
71
+ consecutive_uppercase + consecutive_lowercase + consecutive_numbers
72
+ end
73
+
74
+ # Additions
75
+ def number_of_characters
76
+ password.length * 4
77
+ end
78
+ def uppercase_letters
79
+ n = password.gsub(/[^A-Z]/, '\1').length
80
+ n > 0 ? (length - n) * 2 : 0
81
+ end
82
+ def lowercase_letters
83
+ n = password.gsub(/[^a-z]/, '\1').length
84
+ n > 0 ? (length - n) * 2 : 0
85
+ end
86
+ def numbers
87
+ n = password.gsub(/[^0-9]/, '\1').length
88
+ n < length ? n * 4 : 0
89
+ end
90
+ def symbols
91
+ password.gsub(/[a-zA-Z0-9_]/, '\1').length * 6
92
+ end
93
+ def middle_numbers_or_symbols
94
+ length < 3 ? 0 : password[1...-1].gsub(/[a-zA-Z]/, '\1').length * 2
95
+ end
96
+ def requirements
97
+ if length >= 8
98
+ numbers = password.gsub(/[^0-9]/, '\1').length > 0 ? 1 : 0
99
+ lowercase = password.gsub(/[^a-z]/, '\1').length > 0 ? 1 : 0
100
+ uppercase = password.gsub(/[^A-Z]/, '\1').length > 0 ? 1 : 0
101
+ symbols = password.gsub(/[a-zA-Z0-9_]/, '\1').length > 0 ? 1 : 0
102
+ n = (numbers + lowercase + uppercase + symbols)
103
+ n > 2 ? (n + 1) * 2 : 0 # add 2 for satisfying length
104
+ else
105
+ 0
106
+ end
107
+ end
108
+
109
+ # Deductions
110
+ def letters_only
111
+ n = password.gsub(/[^a-zA-Z]/, '\1').length
112
+ n == length ? n : 0
113
+ end
114
+
115
+ def numbers_only
116
+ n = password.gsub(/[^0-9]/, '\1').length
117
+ n == length ? n : 0
118
+ end
119
+
120
+ def repeated_characters
121
+ nc = ni = 0
122
+ length.times do |a|
123
+ ch_exists = false
124
+ length.times do |b|
125
+ if a != b && password[a] == password[b]
126
+ ch_exists = true
127
+ ni += (length.to_f / (b - a)).abs
128
+ end
129
+ end
130
+ if ch_exists
131
+ nc += 1
132
+ unique = length - nc;
133
+ ni = unique != 0 ? (ni/unique).ceil : ni.ceil
134
+ end
135
+ end
136
+ ni
137
+ end
138
+
139
+ def sequential_letters
140
+ sequential LETTERS, password.downcase
141
+ end
142
+
143
+ def sequential_numbers
144
+ sequential NUMBERS
145
+ end
146
+
147
+ def sequential_symbols
148
+ sequential SYMBOLS
149
+ end
150
+
151
+ def sequential(str, p = password)
152
+ n = 0
153
+ (str.size - 3).times do |i|
154
+ s = str[i..i + 2]
155
+ n += 1 if p.include?( s) || p.include?( s.reverse)
156
+ end
157
+ n * 3
158
+ end
159
+
160
+ def consecutive_uppercase
161
+ consecutive /[A-Z]/
162
+ end
163
+
164
+ def consecutive_lowercase
165
+ consecutive /[a-z]/
166
+ end
167
+
168
+ def consecutive_numbers
169
+ consecutive /[0-9]/
170
+ end
171
+
172
+ def consecutive(pattern)
173
+ n = 0
174
+ prev = nil
175
+ password.chars do |c|
176
+ m = c.match(pattern)
177
+ n += 1 if m && prev
178
+ prev = m
179
+ end
180
+ n * 2
181
+ end
182
+
183
+ end
@@ -0,0 +1,48 @@
1
+ # Copyright (c) 2013 Dynamic Project Management AS
2
+ # Copyright (c) 2013 Knut I. Stenmark
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ class CipherBureau::Statistic < ActiveRecord::Base
24
+ validates_presence_of :country_code, :grammar, :length
25
+
26
+ class << self
27
+ # register updates word statistics
28
+ def register(word)
29
+ stat = where(:country_code => word.country_code, :grammar => word.grammar, :name_type => word.name_type,
30
+ :ascii => word.ascii, :length => word.word.length).first_or_initialize
31
+ stat.word_count += 1
32
+ stat.save!
33
+ stat
34
+ end
35
+
36
+ # returns number of words indatabase based on selection criteria
37
+ #
38
+ # Examples:
39
+ # word_count(5) => number of words with length 5
40
+ # word_count(:ascii => true) number of wordss with true ascii
41
+ # word_count(5, :ascii => true) number of wordsof length 5, with true ascii
42
+ def word_count(*args)
43
+ criteria = args.extract_options!
44
+ criteria.merge!(:length => args.first) if args.first
45
+ where(criteria).sum(:word_count)
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,3 @@
1
+ module CipherBureau
2
+ VERSION = "0.2.1"
3
+ end
@@ -0,0 +1,40 @@
1
+ # Copyright (c) 2013 Dynamic Project Management AS
2
+ # Copyright (c) 2013 Knut I. Stenmark
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ module CipherBureau
24
+ class CreateMigrationGenerator < Rails::Generators::Base
25
+ include Rails::Generators::Migration
26
+ source_root File.expand_path('../../templates', __FILE__)
27
+
28
+ def self.next_migration_number(path)
29
+ @v ||= 0
30
+ @v += 1
31
+ Time.now.utc.strftime("%Y%m%d%H%M%S") + "#{@v}"
32
+ end
33
+
34
+ desc "Creates a migration file for the cipher_bureau_dictionaries tables"
35
+ def create_table_file
36
+ migration_template "create_cipher_bureau_dictionaries.rb", "db/migrate/create_cipher_bureau_dictionaries.rb"
37
+ migration_template "create_cipher_bureau_statistics.rb", "db/migrate/create_cipher_bureau_statistics.rb"
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,36 @@
1
+ # Copyright (c) 2013 Dynamic Project Management AS
2
+ # Copyright (c) 2013 Knut I. Stenmark
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ module CipherBureau
24
+ class LoadDataGenerator < Rails::Generators::Base
25
+ desc "Loads data into the cipher_bureau_dictionaries table. Default language is 'norwegian'."
26
+
27
+ argument :language, :default => 'norwegian'
28
+
29
+ def load_data
30
+ puts "Loading #{language} data"
31
+ load File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'db', 'seeds', language, 'wordloader.rb'))
32
+ puts "Done."
33
+ end
34
+
35
+ end
36
+ end