unpwn 0.3.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 50c1081ffc7e72b8a1e361ad624adf96198a4c6e514591b3594882a2a9def135
4
- data.tar.gz: 65d5f0f41746f64b9cc91861e664c85fd7d9d0f15242459b4a928e9e47bdab18
3
+ metadata.gz: a04f3b1e7997fc330c4ff2069c3e399fd05518ea0d85243518d6477acef7f5a8
4
+ data.tar.gz: 10b25465bd63f35460c6956c53cb918e78a3002523a37af88bcedf888e4960cd
5
5
  SHA512:
6
- metadata.gz: 55b0fead2d885c1ea121c6f188225dfd6ba75a8ddb921c43d188f74d33b2bcc466d2dda1a9fffd7905cd5353ba4b1b5f17a702810a63a04b83f9d819aa37efc1
7
- data.tar.gz: e1479fe39d6fd86d6a450ceb35681c4311d7125ebeb2c9da382301a0d7d13b4bcf8256f5205fcbf969295ff5459c57ac04c741c3b5160f87242249e0dc2d8891
6
+ metadata.gz: 669ab5c727080d5f32d72e5e8a582b6756071965abdb0104a45292a886eb26761f5c5190c6b390136bdfaa049b65084d197c0a3655bed90cec9c388d888bca67
7
+ data.tar.gz: d411bb396f905ade6953c851a1a0a3a6419814696332e2abbc583378a96ef79954f509e8e2882d861bc137b3a30ccc22c209feafb09baafe7dfee7d5d6096cde
data/.travis.yml CHANGED
@@ -4,4 +4,5 @@ language: ruby
4
4
  cache: bundler
5
5
  rvm:
6
6
  - 2.6.0
7
+ - 2.7.1
7
8
  before_install: "gem install 'bundler:~>2.0'"
data/Gemfile.lock CHANGED
@@ -1,15 +1,15 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- unpwn (0.3.0)
4
+ unpwn (1.0.0)
5
5
  bloomer (~> 1.0)
6
- pwned (~> 1.2)
6
+ pwned (~> 2.0)
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
- addressable (2.5.2)
12
- public_suffix (>= 2.0.2, < 4.0)
11
+ addressable (2.8.0)
12
+ public_suffix (>= 2.0.2, < 5.0)
13
13
  bitarray (1.2.0)
14
14
  bloomer (1.0.0)
15
15
  bitarray
@@ -26,10 +26,10 @@ GEM
26
26
  domain_name (~> 0.5)
27
27
  http-form_data (2.1.1)
28
28
  http_parser.rb (0.6.0)
29
- msgpack (1.3.1)
30
- public_suffix (3.0.3)
31
- pwned (1.2.1)
32
- rake (10.5.0)
29
+ msgpack (1.4.2)
30
+ public_suffix (4.0.6)
31
+ pwned (2.3.0)
32
+ rake (12.3.3)
33
33
  rspec (3.8.0)
34
34
  rspec-core (~> 3.8.0)
35
35
  rspec-expectations (~> 3.8.0)
@@ -53,9 +53,9 @@ PLATFORMS
53
53
  DEPENDENCIES
54
54
  bundler (>= 1)
55
55
  http (~> 4.0)
56
- rake (~> 10.0)
56
+ rake (~> 12.3)
57
57
  rspec (~> 3.0)
58
58
  unpwn!
59
59
 
60
60
  BUNDLED WITH
61
- 2.0.1
61
+ 2.2.21
data/lib/unpwn/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  class Unpwn
2
- VERSION = "0.3.0"
2
+ VERSION = "1.0.0"
3
3
  end
data/lib/unpwn.rb CHANGED
@@ -1,13 +1,26 @@
1
1
  require "unpwn/version"
2
2
 
3
- require "bloomer"
4
- require "bloomer/msgpackable"
5
- require "pwned"
6
-
7
- # Unpwn.pwned? tells you if a password should be rejected.
3
+ # Unpwn checks passwords locally against the top one million passwords, as
4
+ # provided by the nbp project. Then, it uses the haveibeenpwned API to check
5
+ # proposed passwords against the largest corpus of publicly dumped passwords in
6
+ # the world.
8
7
  class Unpwn
8
+ class << self
9
+ # Set `offline` to true to disable requests to the haveibeenpwned.com API
10
+ attr_accessor :offline
11
+
12
+ # Check if a password is _not_ already published. To set options like
13
+ # `min`, `max`, or on the Pwned API check, create a new instance of your
14
+ # own.
15
+ def acceptable?(password)
16
+ new.acceptable?(password)
17
+ end
18
+ end
19
+
9
20
  attr_reader :min, :max, :request_options
10
21
 
22
+ # Set the options for an Unpwn instance. `request_options` will be passed
23
+ # verbatim to the `Pwned` library.
11
24
  def initialize(min: 8, max: nil, request_options: nil)
12
25
  raise ArgumentError if min && min < 8
13
26
  raise ArgumentError if max && max < 64
@@ -17,6 +30,7 @@ class Unpwn
17
30
  @request_options = request_options || {}
18
31
  end
19
32
 
33
+ # Check if a password meets the requirements and is not pwned.
20
34
  def acceptable?(password)
21
35
  return false if min && password.size < min
22
36
  return false if max && password.size > max
@@ -24,15 +38,34 @@ class Unpwn
24
38
  !pwned?(password)
25
39
  end
26
40
 
41
+ # Checks if a password is pwned, via bloom filter then `Pwned`.
27
42
  def pwned?(password)
28
- bloom.include?(password) || Pwned.pwned?(password, request_options)
43
+ pwned = bloom.include?(password)
44
+
45
+ unless self.class.offline
46
+ require "pwned"
47
+ pwned ||= Pwned.pwned?(password, request_options)
48
+ end
49
+
50
+ pwned
29
51
  end
30
52
 
31
53
  def bloom
32
54
  @bloom ||= begin
55
+ require "bloomer"
56
+ require "bloomer/msgpackable"
33
57
  top = File.read File.expand_path("top1000000.msgpack", __dir__)
34
58
  Bloomer.from_msgpack(top)
35
59
  end
36
60
  end
37
61
 
62
+ def inspect
63
+ "<UnPwn bloomed=#{@bloom ? 'yes' : 'no'}>"
64
+ end
65
+
66
+ alias :to_s :inspect
67
+ end
68
+
69
+ if defined?(ActiveModel) || defined?(Rails)
70
+ autoload :UnpwnedValidator, "unpwned_validator"
38
71
  end
@@ -0,0 +1,35 @@
1
+ require "unpwn"
2
+
3
+ # Validator class for passwords
4
+ #
5
+ # ==== Examples
6
+ #
7
+ # Validates that attribute is not pwned, but only in production.
8
+ #
9
+ # class User < ActiveRecord::Base
10
+ # validates :password, unpwned: true, if: -> { Rails.env.production? }
11
+ # end
12
+ #
13
+ # Validates that attribute meets min/max and is not pwned.
14
+ #
15
+ # class User < ActiveRecord::Base
16
+ # validates :password, unpwned: { min: 12, max: 128 }
17
+ # end
18
+ class UnpwnedValidator < ActiveModel::EachValidator
19
+ def validate_each(record, attribute, value)
20
+ unpwn = Unpwn.new(**options.slice(:min, :max, :request_options))
21
+
22
+ if unpwn.min && value.length < unpwn.min
23
+ record.errors.add attribute, "is too short"
24
+ end
25
+
26
+ if unpwn.max && value.length > unpwn.max
27
+ record.errors.add attribute, "is too long"
28
+ end
29
+
30
+ if unpwn.pwned?(value)
31
+ record.errors.add attribute, options.fetch(:message,
32
+ "is in common password lists, please choose something more unique")
33
+ end
34
+ end
35
+ end
data/unpwn.gemspec CHANGED
@@ -21,10 +21,10 @@ Gem::Specification.new do |spec|
21
21
  spec.require_paths = ["lib"]
22
22
 
23
23
  spec.add_dependency "bloomer", "~> 1.0"
24
- spec.add_dependency "pwned", "~> 1.2"
24
+ spec.add_dependency "pwned", "~> 2.0"
25
25
 
26
26
  spec.add_development_dependency "bundler", ">= 1"
27
27
  spec.add_development_dependency "http", "~> 4.0"
28
- spec.add_development_dependency "rake", "~> 10.0"
28
+ spec.add_development_dependency "rake", "~> 12.3"
29
29
  spec.add_development_dependency "rspec", "~> 3.0"
30
30
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: unpwn
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andre Arko
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-09-16 00:00:00.000000000 Z
11
+ date: 2021-09-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bloomer
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '1.2'
33
+ version: '2.0'
34
34
  type: :runtime
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: '1.2'
40
+ version: '2.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: bundler
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -72,14 +72,14 @@ dependencies:
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '10.0'
75
+ version: '12.3'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '10.0'
82
+ version: '12.3'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: rspec
85
85
  requirement: !ruby/object:Gem::Requirement
@@ -115,6 +115,7 @@ files:
115
115
  - lib/top1000000.msgpack
116
116
  - lib/unpwn.rb
117
117
  - lib/unpwn/version.rb
118
+ - lib/unpwned_validator.rb
118
119
  - unpwn.gemspec
119
120
  homepage: https://github.com/indirect/unpwn
120
121
  licenses: