bloomed 1.0.0 → 1.1.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
- SHA1:
3
- metadata.gz: c2789813aea4f66b7a6433a8694d60b50d1e7cc5
4
- data.tar.gz: be4191d94d992dfddefb9b512461c0a5b6c1f04b
2
+ SHA256:
3
+ metadata.gz: 527059343640b966e5fb66bd63bbee69553efc8179e6dc5dbcf488461358c010
4
+ data.tar.gz: 35e947c41fab4771cbf58654b806cd984c054ef59764f46f4a44a9440d1f5d49
5
5
  SHA512:
6
- metadata.gz: e8d4bfa81e430496d308a159d8ec513204be4fb2f7939f7e1ff846ee994cae6b7bcf1394b5b6e7a7361e823ef8d0d58f7f92b40818440552f5579400cd90997e
7
- data.tar.gz: b136f1cb1b084fb08b3c74e06ee1799de781a7de964f71d3afd2ea91af66d698f8c4f16869c21c368b9a68f66aa58a42de430a438ec3e997b91bb28e71b92c97
6
+ metadata.gz: e3aecc9a6492e27649e18d79dd3331df0f1bc93b8e375c5307474d4786056eac58684f5645407ba1c4826c87909029093603f7b37fdba229de216558af602782
7
+ data.tar.gz: 2633bc230b66f0d8240dbe75e4a3d0519690db6919383b03b7881524c3f1a58fea25f4e1b03931df6f0d0f2061b7c43986b1d51c0bc823a84e67749282baacb6
@@ -8,7 +8,7 @@ jobs:
8
8
  docker:
9
9
  # specify the version you desire here
10
10
  - image: circleci/ruby:2.5.1-node-browsers
11
-
11
+
12
12
  # Specify service dependencies here if necessary
13
13
  # CircleCI maintains a library of pre-built images
14
14
  # documented at https://circleci.com/docs/2.0/circleci-images/
@@ -35,7 +35,7 @@ jobs:
35
35
  paths:
36
36
  - ./vendor/bundle
37
37
  key: v1-dependencies-{{ checksum "Gemfile.lock" }}
38
-
38
+
39
39
  # Database setup
40
40
  # - run: bundle exec rake db:create
41
41
  # - run: bundle exec rake db:schema:load
@@ -44,16 +44,14 @@ jobs:
44
44
  - run:
45
45
  name: run tests
46
46
  command: |
47
- mkdir /tmp/test-results
48
47
  TEST_FILES="$(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)"
49
-
50
- bundle exec rspec --format progress \
51
- --out /tmp/test-results/rspec.xml \
52
- $TEST_FILES
48
+ mkdir -p /tmp/test_results/rspec
49
+ bundle exec rspec --profile 10 \
50
+ --format RspecJunitFormatter \
51
+ --out /tmp/test_results/rspec/results.xml \
52
+ --format progress \
53
+ $TEST_FILES
53
54
 
54
55
  # collect reports
55
56
  - store_test_results:
56
- path: /tmp/test-results
57
- - store_artifacts:
58
- path: /tmp/test-results
59
- destination: test-results
57
+ path: /tmp/test_results
@@ -2,16 +2,52 @@ PATH
2
2
  remote: .
3
3
  specs:
4
4
  bloomed (1.0.0)
5
- bloomer
5
+ bloomer (~> 1.0)
6
+ msgpack
6
7
 
7
8
  GEM
8
9
  remote: https://rubygems.org/
9
10
  specs:
10
- bitarray (1.1.0)
11
- bloomer (0.0.5)
11
+ bitarray (1.2.0)
12
+ bloomer (1.0.0)
12
13
  bitarray
14
+ msgpack
15
+ coderay (1.1.2)
13
16
  diff-lcs (1.3)
14
- rake (10.5.0)
17
+ ffi (1.9.25)
18
+ formatador (0.2.5)
19
+ guard (2.14.2)
20
+ formatador (>= 0.2.4)
21
+ listen (>= 2.7, < 4.0)
22
+ lumberjack (>= 1.0.12, < 2.0)
23
+ nenv (~> 0.1)
24
+ notiffany (~> 0.0)
25
+ pry (>= 0.9.12)
26
+ shellany (~> 0.0)
27
+ thor (>= 0.18.1)
28
+ guard-compat (1.2.1)
29
+ guard-rspec (4.7.3)
30
+ guard (~> 2.1)
31
+ guard-compat (~> 1.1)
32
+ rspec (>= 2.99.0, < 4.0)
33
+ listen (3.1.5)
34
+ rb-fsevent (~> 0.9, >= 0.9.4)
35
+ rb-inotify (~> 0.9, >= 0.9.7)
36
+ ruby_dep (~> 1.2)
37
+ lumberjack (1.0.13)
38
+ method_source (0.9.0)
39
+ msgpack (1.2.4)
40
+ nenv (0.3.0)
41
+ notiffany (0.1.1)
42
+ nenv (~> 0.1)
43
+ shellany (~> 0.0)
44
+ pry (0.11.3)
45
+ coderay (~> 1.1.0)
46
+ method_source (~> 0.9.0)
47
+ rake (12.3.1)
48
+ rb-fsevent (0.10.3)
49
+ rb-inotify (0.9.10)
50
+ ffi (>= 0.5.0, < 2)
15
51
  rspec (3.8.0)
16
52
  rspec-core (~> 3.8.0)
17
53
  rspec-expectations (~> 3.8.0)
@@ -25,6 +61,11 @@ GEM
25
61
  diff-lcs (>= 1.2.0, < 2.0)
26
62
  rspec-support (~> 3.8.0)
27
63
  rspec-support (3.8.0)
64
+ rspec_junit_formatter (0.4.1)
65
+ rspec-core (>= 2, < 4, != 2.12.0)
66
+ ruby_dep (1.5.0)
67
+ shellany (0.0.1)
68
+ thor (0.20.0)
28
69
 
29
70
  PLATFORMS
30
71
  ruby
@@ -32,8 +73,11 @@ PLATFORMS
32
73
  DEPENDENCIES
33
74
  bloomed!
34
75
  bundler (~> 1.16)
35
- rake (~> 10.0)
76
+ guard
77
+ guard-rspec
78
+ rake (~> 12.0)
36
79
  rspec (~> 3.0)
80
+ rspec_junit_formatter
37
81
 
38
82
  BUNDLED WITH
39
- 1.16.3
83
+ 1.16.4
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Bloomed
2
2
 
3
3
  Troy Hunt's brilliant haveibeenpwned.com let's you download SHA1s of 517,238,891 real world passwords previously exposed in data breaches. This list is comprehensive but huge in size: 11GB compressed.
4
- Using a bloom filter we can reduce the size down to files measured in MBs.
4
+ Using a bloom filter we can reduce the size down to files measured in MBs.
5
5
 
6
6
  You can even keep a the bloom filter in memory in your web app or api. This is great if you're afraid to send the passwords that your users enter, to an external service for lookup.
7
7
 
@@ -29,7 +29,7 @@ Or install it yourself as:
29
29
 
30
30
  ```ruby
31
31
  require 'bloomed'
32
- pw=Bloomed::PW.new
32
+ pw = Bloomed::PW.new
33
33
  pw.pwned? "password123"
34
34
  => true
35
35
  ```
@@ -41,7 +41,7 @@ There are two parameters that can be varied: `top` and `false_positive_probabili
41
41
 
42
42
  ```ruby
43
43
  require 'bloomed'
44
- pw=Bloomed::PW.new(top: 100000, false_positive_probability: 0.01) # 136 kb memory
44
+ pw = Bloomed::PW.new(top: 100000, false_positive_probability: 0.01) # 136 kb memory
45
45
  pw.pwned? "password123"
46
46
  => true
47
47
  ```
@@ -50,20 +50,38 @@ pw.pwned? "password123"
50
50
 
51
51
  To keep the gem size small, it only ships with dumps up to 253 kb in size.
52
52
 
53
- To generate a larger, optimized bloom filter for pwned passwords, please download pwned-passwords-ordered-by-count.7z from https://haveibeenpwned.com and extract `pwned-passwords-ordered-by-count.txt` to the current dir.
53
+ To generate all combinations of `top` and `false_positive_probability` bloom filters for pwned passwords, run:
54
54
 
55
- Once you have the `pwned-passwords-ordered-by-count.txt` file in place, you can run the following to generate the filter and cache it for later (on your machine.)
55
+ `rake seed\[all\]`
56
+
57
+ This will download the source 7zip file with pwned passwords, unpack it to the current dir, write the generated bloom filters in the lib/dump dir relative to the installation path of the gem.
58
+
59
+ Note: You'll need to `brew install curl p7zip` on macos and `apt-get install curl p7zip` on linux.
60
+
61
+ Sometimes you will want to have more precise control of the placement of the cache files. To seed all variants in the current dir, run:
62
+
63
+ ```
64
+ rake seed_here\[all\]
65
+ ```
66
+
67
+ But be aware that it will take a long time!
68
+
69
+ Once you have the massive 22GB text files available, you can generate binary cache files using the exact precision you want.
56
70
 
57
71
  ```ruby
58
72
  require 'bloomed'
59
- pw=Bloomed::PW.new(top: 1E8, false_positive_probability: 0.0001) # 247 Mb! memory
60
- pw.pwned? "password123"
61
- => true
73
+ pw = Bloomed::PW.new(top:1E9, false_positive_probability: 0.0001)
62
74
  ```
63
75
 
64
- ### The cache
76
+ Warning! This seeds all the passwords and will take a loooong time the first time. Even with a binary cache file in place loading it will take massive time and memory.
77
+
78
+ For deployment scenarios where you don't want the server to `rake seed`, you can override the directory used for caching by giving a `cache_dir` argument to the constructor:
65
79
 
66
- The cache is stored in the `dumps` dir inside `dirname $(gem which bloomed)`.
80
+ ```ruby
81
+ require 'bloomed'
82
+ pw = Bloomed::PW.new(top:1E8, false_positive_probability: 0.0001, cache_dir: '/var/lib/bloomed'
83
+ )
84
+ ```
67
85
 
68
86
  ### Size of the in memory bloom filter
69
87
 
data/Rakefile CHANGED
@@ -1,6 +1,21 @@
1
1
  require "bundler/gem_tasks"
2
2
  require "rspec/core/rake_task"
3
+ require_relative 'lib/seeder'
3
4
 
4
5
  RSpec::Core::RakeTask.new(:spec)
5
6
 
6
7
  task :default => :spec
8
+
9
+ task :download do
10
+ unless File.exist? "pwned-passwords-ordered-by-count.txt"
11
+ `curl -O https://downloads.pwnedpasswords.com/passwords/pwned-passwords-ordered-by-count.7z; 7za e pwned-passwords-ordered-by-count.7z; rm pwned-passwords-ordered-by-count.7z;`
12
+ end
13
+ end
14
+
15
+ task :seed, [:all] => [:download] do |_, args|
16
+ Seeder.seed all: args[:all]
17
+ end
18
+
19
+ task :seed_here, [:all] => [:download] do |_, args|
20
+ Seeder.seed all: args[:all], cache_dir: Dir.getwd
21
+ end
@@ -23,9 +23,13 @@ Gem::Specification.new do |spec|
23
23
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
24
24
  spec.require_paths = ["lib"]
25
25
 
26
- spec.add_dependency "bloomer"
26
+ spec.add_dependency "bloomer", "~> 1.0"
27
+ spec.add_dependency "msgpack"
27
28
 
28
29
  spec.add_development_dependency "bundler", "~> 1.16"
29
- spec.add_development_dependency "rake", "~> 10.0"
30
+ spec.add_development_dependency "rake", "~> 12.0"
30
31
  spec.add_development_dependency "rspec", "~> 3.0"
32
+ spec.add_development_dependency "guard"
33
+ spec.add_development_dependency "guard-rspec"
34
+ spec.add_development_dependency "rspec_junit_formatter"
31
35
  end
@@ -1,11 +1,22 @@
1
- require_relative 'bloomed/version'
2
- require 'bloomer'
1
+ require_relative "bloomed/version"
2
+ require_relative "bloomed/msg_packable"
3
+ require "bloomer"
4
+ require "bloomer/msgpackable"
3
5
 
4
6
  module Bloomed
5
7
  class PW
6
- attr_reader :false_positive_probability, :top
8
+ include MsgPackable::Bloomed
7
9
 
8
- def initialize(top: 100_000, false_positive_probability: 0.001)
10
+ attr_reader :false_positive_probability,
11
+ :top,
12
+ :bloom,
13
+ :cache_dir,
14
+ :filename
15
+
16
+ def initialize(top: 100_000,
17
+ false_positive_probability: 0.001,
18
+ cache_dir: nil)
19
+ @cache_dir = cache_dir || File.join(File.dirname(__FILE__), "dump")
9
20
  @top = top
10
21
  @false_positive_probability = false_positive_probability
11
22
  @bloom = prepare
@@ -16,14 +27,20 @@ module Bloomed
16
27
  end
17
28
 
18
29
  def memory_size_bytes
19
- require 'objspace'
30
+ require "objspace"
20
31
  ObjectSpace.memsize_of(@bloom)
21
32
  end
22
33
 
34
+ def filename
35
+ inverse_probaility = 1.0 / false_positive_probability
36
+ File.join(cache_dir,
37
+ "pwned_top_#{top.to_i}_one_in_#{inverse_probaility.to_i}.msgpk")
38
+ end
39
+
23
40
  private
24
41
 
25
42
  def prepare
26
- if File.exist? file_name
43
+ if File.exist? filename
27
44
  load_cache
28
45
  else
29
46
  bloom_filter = generate
@@ -32,38 +49,30 @@ module Bloomed
32
49
  end
33
50
  end
34
51
 
35
- def file_name
36
- inverse_probaility = 1.0 / false_positive_probability
37
- File.join(
38
- File.dirname(__FILE__),
39
- 'dump',
40
- "pwned_top_#{top.to_i}_one_in_#{inverse_probaility.to_i}.dump"
41
- )
42
- end
43
-
44
52
  def load_cache
45
- Marshal.load(File.read(file_name))
53
+ Bloomed::PW.from_msgpack(File.read(filename))
46
54
  end
47
55
 
48
- PWNED_PASSWORDS_FILENAME = 'pwned-passwords-ordered-by-count.txt'.freeze
56
+ PWNED_PASSWORDS_FILENAME = "pwned-passwords-ordered-by-count.txt".freeze
57
+
49
58
  def generate
50
59
  unless File.exist? PWNED_PASSWORDS_FILENAME
51
- raise "In order to generate new, optimized bloom filter for
52
- pwned passwords, please download pwned-passwords-ordered-by-count.7z from
53
- https://haveibeenpwned.com and extract pwned-passwords-ordered-by-count.txt
54
- to the current dir."
60
+ raise MissingPasswordListError, "To generate new, optimized pwned passwords bloom filter, run `rake seed` or `rake seed_here`. To generate all variants, even the very large binaries, run `rake seed\[all\]` or `rake seed_here\[all\]`."
55
61
  end
56
62
 
57
- bloom_filter = Bloomer::Scalable.new(top, false_positive_probability)
58
- File.open(PWNED_PASSWORDS_FILENAME, 'r').first(top).each do |line|
63
+ bloom_filter = Bloomer.new(top, false_positive_probability)
64
+ File.open(PWNED_PASSWORDS_FILENAME, "r").first(top).each do |line|
59
65
  bloom_filter.add line[0...40]
60
66
  end
61
67
  bloom_filter
62
68
  end
63
69
 
64
70
  def write_cache(b)
65
- File.write(file_name, Marshal.dump(b))
71
+ File.write(filename, b.to_msgpack)
66
72
  b
67
73
  end
68
74
  end
75
+
76
+ class MissingPasswordListError < RuntimeError
77
+ end
69
78
  end
@@ -0,0 +1,45 @@
1
+ require 'msgpack'
2
+
3
+ module MsgPackable
4
+ module Bloomed
5
+ def self.included(base)
6
+ base.extend(ClassMethods)
7
+ end
8
+
9
+ def to_msgpack_ext
10
+ self.class.msgpack_factory.dump([@top, @false_positive_probability, @bloom])
11
+ end
12
+
13
+ def from_msgpack_ext(top, false_positive_probability, bloom)
14
+ @top = top
15
+ @false_positive_probability = false_positive_probability
16
+ @bloom = bloom
17
+ end
18
+
19
+ def to_msgpack
20
+ self.class.msgpack_factory.dump self
21
+ end
22
+
23
+ module ClassMethods
24
+ def from_msgpack(data)
25
+ msgpack_factory.load(data)
26
+ end
27
+
28
+ def from_msgpack_ext(data)
29
+ values = msgpack_factory.load(data)
30
+ ::Bloomed::PW.new.tap do |b|
31
+ b.from_msgpack_ext(*values)
32
+ end
33
+ end
34
+
35
+ def msgpack_factory
36
+ @msgpack_factory ||= ::MessagePack::Factory.new.tap do |factory|
37
+ factory.register_type(0x01, ::Bloomer)
38
+ factory.register_type(0x02, ::Bloomer::Scalable)
39
+ factory.register_type(0x03, ::Bloomed::PW)
40
+ factory.freeze
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -1,3 +1,3 @@
1
1
  module Bloomed
2
- VERSION = "1.0.0"
2
+ VERSION = "1.1.0"
3
3
  end
@@ -0,0 +1,21 @@
1
+ require "./lib/bloomed"
2
+
3
+ KB = 2 ** 10
4
+
5
+ module Seeder
6
+ def self.seed(all: false, cache_dir: nil)
7
+ ps = [0.01, 0.001, 0.0001]
8
+ cs = [1E4, 1E5]
9
+
10
+ if all
11
+ cs += [1E6, 1E7, 1E8]
12
+ end
13
+
14
+ cs.product(ps).each do |c, p|
15
+ print "Generating filter for top #{c.to_i} with #{p} precision "
16
+ b = Bloomed::PW.new(top: c, false_positive_probability: p, cache_dir: cache_dir)
17
+ size = File.size(b.filename)
18
+ puts "Done [#{size / KB} kb]"
19
+ end
20
+ end
21
+ end
metadata CHANGED
@@ -1,17 +1,31 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bloomed
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Søren Skovsbøll
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-09-02 00:00:00.000000000 Z
11
+ date: 2018-09-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bloomer
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: msgpack
15
29
  requirement: !ruby/object:Gem::Requirement
16
30
  requirements:
17
31
  - - ">="
@@ -44,14 +58,14 @@ dependencies:
44
58
  requirements:
45
59
  - - "~>"
46
60
  - !ruby/object:Gem::Version
47
- version: '10.0'
61
+ version: '12.0'
48
62
  type: :development
49
63
  prerelease: false
50
64
  version_requirements: !ruby/object:Gem::Requirement
51
65
  requirements:
52
66
  - - "~>"
53
67
  - !ruby/object:Gem::Version
54
- version: '10.0'
68
+ version: '12.0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: rspec
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -66,6 +80,48 @@ dependencies:
66
80
  - - "~>"
67
81
  - !ruby/object:Gem::Version
68
82
  version: '3.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: guard
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: guard-rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rspec_junit_formatter
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
69
125
  description: Check your users' passwords using a fraction of the memory of the full
70
126
  pwned passwords list.
71
127
  email:
@@ -89,14 +145,15 @@ files:
89
145
  - bin/setup
90
146
  - bloomed.gemspec
91
147
  - lib/bloomed.rb
148
+ - lib/bloomed/msg_packable.rb
92
149
  - lib/bloomed/version.rb
93
- - lib/dump/pwned_top_100000_one_in_100.dump
94
- - lib/dump/pwned_top_100000_one_in_1000.dump
95
- - lib/dump/pwned_top_100000_one_in_10000.dump
96
- - lib/dump/pwned_top_10000_one_in_100.dump
97
- - lib/dump/pwned_top_10000_one_in_1000.dump
98
- - lib/dump/pwned_top_10000_one_in_10000.dump
99
- - lib/seed.rb
150
+ - lib/dump/pwned_top_100000_one_in_100.msgpk
151
+ - lib/dump/pwned_top_100000_one_in_1000.msgpk
152
+ - lib/dump/pwned_top_100000_one_in_10000.msgpk
153
+ - lib/dump/pwned_top_10000_one_in_100.msgpk
154
+ - lib/dump/pwned_top_10000_one_in_1000.msgpk
155
+ - lib/dump/pwned_top_10000_one_in_10000.msgpk
156
+ - lib/seeder.rb
100
157
  homepage: https://github.com/skovsboll/bloomed
101
158
  licenses:
102
159
  - MIT
@@ -117,7 +174,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
117
174
  version: '0'
118
175
  requirements: []
119
176
  rubyforge_project:
120
- rubygems_version: 2.5.2.3
177
+ rubygems_version: 2.7.6
121
178
  signing_key:
122
179
  specification_version: 4
123
180
  summary: Bloom filter check for pwned passwords
@@ -1,8 +0,0 @@
1
- require './lib/bloomed'
2
-
3
- ps = [0.01, 0.001, 0.0001]
4
- cs = [1E4, 1E5, 1E6, 1E7, 1E8]
5
-
6
- cs.product(ps).each do |c, p|
7
- b = Bloomed::PW.new(first: c, false_positive_probability: p)
8
- end