nobspw 0.5.0 → 0.6.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 50bde3af21d4ae1a914fdf29d97c7cd4636f9045d12053b19b03b10562432200
4
- data.tar.gz: bb15b53c7660e771fd4d0d430be1882186d11515662d1ffe9f221478f4df0013
3
+ metadata.gz: d81c15016a1b06dc3d38fc995120b526574a65cd5fd13ed98bc05e614f189b5b
4
+ data.tar.gz: a7303590e8fa254ad9718fda4444a2c3d5faabb77cc528d5a5284e52792742be
5
5
  SHA512:
6
- metadata.gz: f8688c43975ea97d01f0bb39d8213dd221f7e4ec1022cba7b068e079c7e6213a826dc36949b90582ca2e3e8a23b9f7e9388904357c2166deaf5ef614ea646f83
7
- data.tar.gz: 1c2f2a8835ab93d53bcb187bc7eb86123280d2c831114a7c5f26822708ee44ac1d20ac41c797a8a9b0d57543a44a0de3c3bcb1104a6f4cbea2c8c4033e9db871
6
+ metadata.gz: 2e8b250a5a326593bab9f576cdc7ec15da4e03573c273bacc62b74f46c4977df5e323b079aa43f613d17f458f1417b1f569e2f7dd19f190be16af5b0b68e7a13
7
+ data.tar.gz: 6ab6462e6c32b58a1f79cd01ffa0a540fab446f22db43b43c52366821a3a185f7c5a1c5b78cd938f4a5be94c2f93ba1cc094f9a456c8d957c68cfa079c7a2cba
@@ -1,7 +1,7 @@
1
1
  sudo: false
2
2
  language: ruby
3
3
  rvm:
4
- - 2.3.3
5
- - 2.4.0
6
4
  - 2.5.0
7
- before_install: gem install bundler -v 1.14.2
5
+ - 2.6.2
6
+ - 2.7.1
7
+ before_install: gem install bundler
data/README.md CHANGED
@@ -60,6 +60,7 @@ Optionally, you can configure some options:
60
60
  config.min_unique_characters = 5
61
61
  config.dictionary_path = 'path/to/dictionary.txt'
62
62
  config.grep_path = '/usr/bin/grep'
63
+ config.use_ruby_grep = false # Defaults to false; slower when true. Uses Ruby's internal Grep method instead of shelling out.
63
64
  config.domain_name = 'mywebsitedomain.com' # it is recommended you configure this
64
65
  config.blacklist = ['this_password_is_not_allowed', /password/]
65
66
  end
@@ -70,7 +71,7 @@ Optionally, you can configure some options:
70
71
  I included `PasswordValidator` for Rails. Validating passwords in your model couldn't be easier:
71
72
 
72
73
  ```ruby
73
- validates :password, presence: true, password: true, if: -> { new_record? || changes[:password] }
74
+ validates :password, presence: true, password: true, if: -> { new_record? || changes[:password] || changes[:password_digest] }
74
75
  ```
75
76
 
76
77
  PasswordValidator will try to guess the correct field name for each `PasswordChecker` argument as follow:
@@ -84,7 +85,7 @@ If you have field names different than above, you can tell `PasswordValidator` w
84
85
  ```ruby
85
86
  validates :password, password: { :name => :customer_name,
86
87
  :email => :electronic_address },
87
- if: -> { new_record? || changes[:password] }
88
+ if: -> { new_record? || changes[:password] || changes[:password_digest] }
88
89
  ```
89
90
 
90
91
  ## Validations
@@ -5,6 +5,7 @@ module NOBSPW
5
5
  attr_accessor :min_unique_characters
6
6
  attr_accessor :dictionary_path
7
7
  attr_accessor :grep_path
8
+ attr_accessor :use_ruby_grep
8
9
  attr_accessor :domain_name
9
10
  attr_accessor :blacklist
10
11
  attr_accessor :validation_methods
@@ -16,6 +17,7 @@ module NOBSPW
16
17
  @min_unique_characters = 5
17
18
  @dictionary_path = File.join(File.dirname(__FILE__), "..", "db", "dictionary.txt")
18
19
  @grep_path = `which grep`.strip
20
+ @use_ruby_grep = @grep_path.empty?
19
21
  @domain_name = nil
20
22
  @blacklist = nil
21
23
  @validation_methods = NOBSPW::ValidationMethods::DEFAULT_VALIDATION_METHODS
@@ -1,3 +1,5 @@
1
+ require 'shellwords'
2
+
1
3
  module NOBSPW
2
4
  class PasswordChecker
3
5
  include NOBSPW::ValidationMethods
@@ -35,9 +37,5 @@ module NOBSPW
35
37
 
36
38
  @strong = @weak_password_reasons.empty?
37
39
  end
38
-
39
- def grep_command(path)
40
- "#{NOBSPW.configuration.grep_path} '^#{@password}$' #{path}"
41
- end
42
40
  end
43
41
  end
@@ -1,3 +1,6 @@
1
+ require 'shellwords'
2
+ require 'open3'
3
+
1
4
  module NOBSPW
2
5
  module ValidationMethods
3
6
  DEFAULT_VALIDATION_METHODS = %i(password_empty?
@@ -12,6 +15,8 @@ module NOBSPW
12
15
  password_too_common?)
13
16
 
14
17
  INTERRUPT_VALIDATION_FOR = %i(password_empty?)
18
+ STDIN_GREP_COMMAND = ['/usr/bin/grep', '-m 1', '-f', '/dev/stdin',
19
+ NOBSPW.configuration.dictionary_path]
15
20
 
16
21
  private
17
22
 
@@ -81,22 +86,27 @@ module NOBSPW
81
86
  end
82
87
 
83
88
  def password_too_common?
84
- `#{grep_command(NOBSPW.configuration.dictionary_path)}`
85
-
86
- case $?.exitstatus
87
- when 0
88
- true
89
- when 1
90
- false
91
- when 127
92
- raise StandardError.new("Grep not found at: #{NOBSPW.configuration.grep_path}")
93
- else
94
- false
95
- end
89
+ NOBSPW.configuration.use_ruby_grep ? ruby_grep : shell_grep
96
90
  end
97
91
 
98
92
  # Helper methods
99
93
 
94
+ def shell_grep
95
+ raise StandardError.new("Grep not found at: #{NOBSPW.configuration.grep_path}") \
96
+ if !File.exist?(NOBSPW.configuration.grep_path)
97
+
98
+ output = Open3.popen3(STDIN_GREP_COMMAND.join(" "), out: '/dev/null') { |stdin, stdout, stderr, wait_thr|
99
+ stdin.puts "^#{escaped_password}$"
100
+ stdin.close
101
+ wait_thr.value
102
+ }
103
+ output.success?
104
+ end
105
+
106
+ def ruby_grep
107
+ File.open(NOBSPW.configuration.dictionary_path).grep(/^#{escaped_password}$/).any?
108
+ end
109
+
100
110
  def email_without_extension(email)
101
111
  name, domain, whatev = email&.split("@", 3)
102
112
  "#{name}@#{strip_extension_from_domain(domain)}"
@@ -110,5 +120,8 @@ module NOBSPW
110
120
  str&.gsub(/-|_|\.|\'|\"|\@/, ' ')
111
121
  end
112
122
 
123
+ def escaped_password(password = @password)
124
+ Shellwords.escape(password)
125
+ end
113
126
  end
114
127
  end
@@ -1,3 +1,3 @@
1
1
  module NOBSPW
2
- VERSION = '0.5.0'
2
+ VERSION = '0.6.2'
3
3
  end
@@ -0,0 +1,73 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ require 'benchmark'
4
+ require 'shellwords'
5
+ require 'open3'
6
+ require 'subprocess'
7
+
8
+ ITERATIONS = 100
9
+ DICTIONARY_PATH = File.join(File.dirname(__FILE__), '..', 'lib/db/dictionary.txt')
10
+ STDIN_GREP_COMMAND = ['/usr/bin/grep', '-m 1', '-f', '/dev/stdin', DICTIONARY_PATH]
11
+
12
+ password = 'swordfish'
13
+
14
+ def shell_grep(password)
15
+ password = Shellwords.escape(password)
16
+ `/usr/bin/grep -m 1 '^#{password}$' #{DICTIONARY_PATH}`
17
+ $?.exitstatus == 0
18
+ end
19
+
20
+ def shell_grep_open3(password)
21
+ password = Shellwords.escape(password)
22
+
23
+ output = Open3.popen3(STDIN_GREP_COMMAND.join(" "), out: '/dev/null') { |stdin, stdout, stderr, wait_thr|
24
+ stdin.puts "^#{password}$"
25
+ stdin.close
26
+ wait_thr.value
27
+ }
28
+ output.success?
29
+ end
30
+
31
+ def shell_grep_subprocess(password)
32
+ password = Shellwords.escape(password)
33
+
34
+ Subprocess.check_call(STDIN_GREP_COMMAND, stdin: Subprocess::PIPE, stdout: '/dev/null') do |p|
35
+ p.communicate("^#{password}$")
36
+ end
37
+ true
38
+ rescue Subprocess::NonZeroExit
39
+ false
40
+ end
41
+
42
+ def ruby_grep(password)
43
+ File.open(DICTIONARY_PATH).grep(/^#{password}$/)
44
+ end
45
+
46
+ def ruby_loop(password)
47
+ File.open(DICTIONARY_PATH).read_line do |l|
48
+ return true if l.match?(/^#{password}$/)
49
+ end
50
+ false
51
+ end
52
+
53
+ Benchmark.bm(17) do |benchmark|
54
+ benchmark.report("Shell") do
55
+ ITERATIONS.times { shell_grep(password) }
56
+ end
57
+
58
+ benchmark.report("Ruby Grep") do
59
+ ITERATIONS.times { ruby_grep(password) }
60
+ end
61
+
62
+ benchmark.report("Ruby Loop") do
63
+ ITERATIONS.times { ruby_grep(password) }
64
+ end
65
+
66
+ benchmark.report("Open3 stdin") do
67
+ ITERATIONS.times { shell_grep_open3(password) }
68
+ end
69
+
70
+ benchmark.report("Subprocess stdin") do
71
+ ITERATIONS.times { shell_grep_subprocess(password) }
72
+ end
73
+ end
@@ -21,14 +21,15 @@ Gem::Specification.new do |spec|
21
21
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
22
  spec.require_paths = ["lib"]
23
23
 
24
- spec.add_development_dependency "bundler", "~> 1.14"
25
- spec.add_development_dependency "rake", "~> 10.0"
24
+ spec.add_development_dependency "bundler"
25
+ spec.add_development_dependency "rake", "~> 12.3.3"
26
26
  spec.add_development_dependency "rspec", "~> 3.0"
27
27
  spec.add_development_dependency "simplecov", "~> 0.13"
28
28
  spec.add_development_dependency "guard", "~> 2.14"
29
29
  spec.add_development_dependency "guard-rspec", "~> 4.7.3"
30
30
  spec.add_development_dependency "activemodel", "~> 5.0"
31
31
  spec.add_development_dependency "i18n", "~> 0.8.1"
32
+ spec.add_development_dependency "subprocess"
32
33
  spec.add_development_dependency "byebug"
33
34
 
34
35
  if RUBY_PLATFORM =~ /darwin/
metadata CHANGED
@@ -1,43 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nobspw
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Carl Mercier
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-02-21 00:00:00.000000000 Z
11
+ date: 2020-06-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '1.14'
19
+ version: '0'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '1.14'
26
+ version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
33
+ version: 12.3.3
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '10.0'
40
+ version: 12.3.3
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -122,6 +122,20 @@ dependencies:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
124
  version: 0.8.1
125
+ - !ruby/object:Gem::Dependency
126
+ name: subprocess
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
125
139
  - !ruby/object:Gem::Dependency
126
140
  name: byebug
127
141
  requirement: !ruby/object:Gem::Requirement
@@ -189,6 +203,7 @@ files:
189
203
  - lib/nobspw/password_checker.rb
190
204
  - lib/nobspw/validation_methods.rb
191
205
  - lib/nobspw/version.rb
206
+ - misc/grep_benchmark.rb
192
207
  - nobspw.gemspec
193
208
  homepage: https://github.com/cmer/nobspw
194
209
  licenses:
@@ -209,8 +224,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
209
224
  - !ruby/object:Gem::Version
210
225
  version: '0'
211
226
  requirements: []
212
- rubyforge_project:
213
- rubygems_version: 2.7.6
227
+ rubygems_version: 3.1.2
214
228
  signing_key:
215
229
  specification_version: 4
216
230
  summary: No Bullshit Password strength checker