rack-address_munging 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: '0009c47a3ddb287023fd4a5fa33d7829862b8b97'
4
+ data.tar.gz: dc0c58999b312febe87685f553ca042a6c4cb667
5
+ SHA512:
6
+ metadata.gz: 579dc7548505cc0adf879989cf0a6729d3c2693e0526d03974dc965e9c37ff154471f8c78bfa7795ae1fe80d81862a0c33ec0a16a0e13f0dcd8687c9c5913ae8
7
+ data.tar.gz: 7b0a2e00f16816470029a9bd01c26d8a9cdcda1f3f6aab76bb09f804653359d0b8a3838bba5eaf5b0fdcaf3d65ea5b3cd885f20c35a504bc0bc69673b3276b36
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,5 @@
1
+ Metrics/LineLength:
2
+ Max: 150
3
+
4
+ Style/Semicolon:
5
+ Enabled: false
data/.travis.yml ADDED
@@ -0,0 +1,11 @@
1
+ language: ruby
2
+ sudo: false
3
+ script: "bundle exec rake clean spec"
4
+
5
+ rvm:
6
+ - 2.2
7
+ - 2.3
8
+ - 2.4
9
+
10
+ gemfile:
11
+ - Gemfile
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in rack-address_munging.gemspec
6
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,57 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ rack-address_munging (0.1.1)
5
+ mail (> 2.5.0)
6
+ rack (>= 0.9.1)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ ast (2.4.0)
12
+ diff-lcs (1.3)
13
+ mail (2.7.0)
14
+ mini_mime (>= 0.1.1)
15
+ mini_mime (1.0.0)
16
+ parallel (1.12.1)
17
+ parser (2.5.0.3)
18
+ ast (~> 2.4.0)
19
+ powerpack (0.1.1)
20
+ rack (2.0.4)
21
+ rainbow (3.0.0)
22
+ rake (10.5.0)
23
+ rspec (3.7.0)
24
+ rspec-core (~> 3.7.0)
25
+ rspec-expectations (~> 3.7.0)
26
+ rspec-mocks (~> 3.7.0)
27
+ rspec-core (3.7.1)
28
+ rspec-support (~> 3.7.0)
29
+ rspec-expectations (3.7.0)
30
+ diff-lcs (>= 1.2.0, < 2.0)
31
+ rspec-support (~> 3.7.0)
32
+ rspec-mocks (3.7.0)
33
+ diff-lcs (>= 1.2.0, < 2.0)
34
+ rspec-support (~> 3.7.0)
35
+ rspec-support (3.7.1)
36
+ rubocop (0.53.0)
37
+ parallel (~> 1.10)
38
+ parser (>= 2.5)
39
+ powerpack (~> 0.1)
40
+ rainbow (>= 2.2.2, < 4.0)
41
+ ruby-progressbar (~> 1.7)
42
+ unicode-display_width (~> 1.0, >= 1.0.1)
43
+ ruby-progressbar (1.9.0)
44
+ unicode-display_width (1.3.0)
45
+
46
+ PLATFORMS
47
+ ruby
48
+
49
+ DEPENDENCIES
50
+ bundler (~> 1.16)
51
+ rack-address_munging!
52
+ rake (~> 10.0)
53
+ rspec (~> 3.7.0)
54
+ rubocop
55
+
56
+ BUNDLED WITH
57
+ 1.16.1
data/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright 2018 notus.sh
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,63 @@
1
+ # Rack::AddressMunging
2
+
3
+ [![Build Status](https://travis-ci.org/notus-sh/rack-address_munging.svg?branch=master)](https://travis-ci.org/notus-sh/rack-address_munging)
4
+
5
+ `Rack::AddressMunging` is a Rack middleware for automatic [e-mail addresses munging](https://en.wikipedia.org/wiki/Address_munging).
6
+
7
+ Once added to your middleware stack, `Rack::AddressMunging` will parse the body of any HTML response and mung it to obfuscate email addresses, in hope to prevent spambots to collect them too easily.
8
+
9
+ ## Installation
10
+
11
+ `Rack::AddressMunging` is distributed as a gem and available on [rubygems.org](https://rubygems.org/gems/rack-address_munging) so you can add it to your `Gemfile` or install it manually with:
12
+
13
+ ```ruby
14
+ gem install rack-address_munging
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ To use the middleware with it's default configuration, just drop it in your middleware stack:
20
+
21
+ ```ruby
22
+ # In config.ru or wherever your stack is defined
23
+ require 'rack/address_munging'
24
+
25
+ use Rack::AddressMunging
26
+ ```
27
+
28
+ If you want to use another munging strategy, precise it as an argument:
29
+
30
+ ```ruby
31
+ # In a Rails initializer
32
+ require 'rack/address_munging'
33
+
34
+ module YourRailsAppName
35
+ class Application
36
+ config.middleware.use Rack::AddressMunging, strategy: :hex
37
+ end
38
+ end
39
+ ```
40
+
41
+ ## Supported Strategies
42
+
43
+ ### `:Hex`
44
+
45
+ Replace email addresses and mailto href attributes values with an hexadecimal entities alternative.
46
+
47
+ Input: email@example.com
48
+ Output: &#101;&#109;&#97;&#105;&#108;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;
49
+
50
+ `:Hex` is the default strategy.
51
+
52
+ ### `:Rot13JS`
53
+
54
+ Replace email addresses and full mailto links with a `<script>` tag that will print it back into the page, based on a [ROT13](https://en.wikipedia.org/wiki/ROT13) version.
55
+
56
+ Input: email@example.com
57
+ Output: <script type="text/javascript">document.write("rznvy(at)rknzcyr.pbz".replace(/(at)/, '@').replace(/[a-z]/gi,function(c){return String.fromCharCode((c<="Z"?90:122)>=(c=c.charCodeAt(0)+13)?c:c-26);});))</script>
58
+
59
+ For more informations about the exact behavior of each strategy, please refer to the [strategies specs data](https://github.com/notus-sh/rack-address_munging/blob/master/spec/data/strategy.yml).
60
+
61
+ ## Contributing
62
+
63
+ Bug reports and pull requests are welcome on GitHub at <https://github.com/notus-sh/rack-address_munging>.
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+
5
+ require 'rspec/core/rake_task'
6
+ RSpec::Core::RakeTask.new
7
+
8
+ require 'rubocop/rake_task'
9
+ RuboCop::RakeTask.new
10
+
11
+ task default: :spec
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mail'
4
+ require 'ipaddr'
5
+
6
+ module Rack
7
+ class AddressMunging
8
+ # This module contains email address detection and validation methods.
9
+ # It is meant to be included in any munging strategy.
10
+ module Detection
11
+ REGEXP_EMAIL = /[a-z0-9][^@\s'":<>]+@[^@\s'":<>]+[a-z0-9]/i
12
+ REGEXP_MAILTO = /mailto:#{REGEXP_EMAIL}/i
13
+ REGEXP_LINK = %r{<a[^>]+?href="#{REGEXP_MAILTO}"[^>]*?>.+?</a>}i
14
+
15
+ def email?(string)
16
+ m = ::Mail::Address.new(string)
17
+ return false unless m.address == string
18
+ return false unless valid_local?(m.local)
19
+ return false unless valid_domain?(m.domain)
20
+ true
21
+ rescue StandardError
22
+ false
23
+ end
24
+
25
+ private
26
+
27
+ def valid_local?(local)
28
+ return false if local.include?('..') # Can't contain ..
29
+ return false if local.include?('@') # Can't contain an @
30
+ return false unless local !~ /^"?\s+"?$/ # Can't be blank
31
+ true
32
+ end
33
+
34
+ def valid_domain?(domain)
35
+ return false if ip_address?(domain)
36
+ return false if local_domain?(domain)
37
+ return false if hires_image?(domain)
38
+ return false if domain.include?('..') # Can't contain ..
39
+ true
40
+ end
41
+
42
+ def ip_address?(domain)
43
+ ip = IpAddr.new(domain)
44
+ ip.to_s == domain
45
+ rescue StandardError
46
+ false
47
+ end
48
+
49
+ def local_domain?(domain)
50
+ !domain.include?('.') # Must contain at least a .
51
+ end
52
+
53
+ # /path/to/image@2x.format should not be matched as a valid email
54
+ # Hashed version of the path shouldn't match either
55
+ def hires_image?(domain)
56
+ !(domain !~ /^\dx\.(jpe?g|gif|png|webp)$/ && domain !~ /^\dx-[0-9a-f]{32}\.(jpe?g|gif|png|webp)$/)
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rack
4
+ class AddressMunging
5
+ module Strategy
6
+ # The <tt>:Hex</tt> munging strategy
7
+ #
8
+ # Will replace email addresses and mailto href attributes values with
9
+ # an hexadecimal HTML entities alternative.
10
+ class Hex
11
+ include Detection
12
+
13
+ def apply(munged, original)
14
+ original.each do |part|
15
+ part = part.dup if part.frozen?
16
+ part.gsub!(REGEXP_MAILTO) { |m| maybe_encode(m) }
17
+ part.gsub!(REGEXP_EMAIL) { |m| maybe_encode(m) }
18
+ munged.write part
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def maybe_encode(string)
25
+ s = to_s(string)
26
+ email?(s.gsub(/^mailto:/, '')) ? encode(s) : s
27
+ end
28
+
29
+ def encode(str)
30
+ to_s(str).unpack('C*').map { |c| format('&#%<c>d;', c: c) }.join
31
+ end
32
+
33
+ # Normalize a match as a string
34
+ # (gsub return ActiveSupport::SafeBuffer when ActiveSupport is loaded)
35
+ def to_s(string)
36
+ string.respond_to?(:to_str) ? string.to_str : string.try(:to_s)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rack
4
+ class AddressMunging
5
+ module Strategy
6
+ # The <tt>:Rot13JS</tt> munging strategy
7
+ #
8
+ # Will replace email addresses and full mailto links with a <tt><script></tt> tag
9
+ # that will print it back into the page, based on a ROT13 version.
10
+ #
11
+ # The ROT13 implementation used here is a bit different as the original one will not
12
+ # replace <tt>@</tt>. This fix it, applying a second replacement to switch <tt>@</tt>
13
+ # with <tt>(at)</tt> in the munged string.
14
+ #
15
+ # This strategy does not handle email addresses containing UTF-8 entities.
16
+ class Rot13JS
17
+ include Detection
18
+
19
+ def apply(munged, original)
20
+ original.each do |part|
21
+ part = part.dup if part.frozen?
22
+ part.gsub!(REGEXP_LINK) { |m| maybe_encode(m) }
23
+ part.gsub!(REGEXP_EMAIL) { |m| maybe_encode(m) }
24
+ munged.write part
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def maybe_encode(string)
31
+ s = to_s(string)
32
+ s.scan(REGEXP_EMAIL).collect { |m| email?(to_s(m)) }.any? ? encode(s) : s
33
+ end
34
+
35
+ def encode(str)
36
+ <<-ENCODED.strip
37
+ <script type="text/javascript">document.write("#{to_s(str).tr('A-Za-z', 'N-ZA-Mn-za-m').gsub('@', '(at)')}".replace(/\(at\)/, '@').replace(/[a-z]/gi,function(c){return String.fromCharCode((c<="Z"?90:122)>=(c=c.charCodeAt(0)+13)?c:c-26);});))</script>
38
+ ENCODED
39
+ end
40
+
41
+ # Normalize a match as a string
42
+ # (gsub return ActiveSupport::SafeBuffer when ActiveSupport is loaded)
43
+ def to_s(string)
44
+ string.respond_to?(:to_str) ? string.to_str : string.try(:to_s)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rack
4
+ class AddressMunging
5
+ # This module group all available munging strategies.
6
+ #
7
+ # When the Rack::AddressMunging middleware is instanciated, the required
8
+ # strategy is loaded as a child constant of this module. If you want to
9
+ # write your own munging strategy, you must create it as a subclass of
10
+ # <tt>Rack::AddressMunging::Strategy</tt> for it to be usable.
11
+ module Strategy
12
+ autoload :Hex, 'rack/address_munging/strategy/hex'
13
+ autoload :Rot13JS, 'rack/address_munging/strategy/rot13js'
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rack
4
+ class AddressMunging
5
+ VERSION = '0.1.1'
6
+ end
7
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rack/response'
4
+
5
+ module Rack
6
+ # The Rack::AddressMunging middleware, meant to be used in your Rack stack.
7
+ #
8
+ # All other modules meant for use in your application are <tt>autoload</tt>ed here,
9
+ # so it should be enough just to <tt>require 'rack/address_munging'</tt> in your code.
10
+ #
11
+ # To add the middleware to your stack, use:
12
+ # <code>use Rack::AddressMunging</code>
13
+ #
14
+ # If you want to use another munging strategy, precise it as an argument:
15
+ # <code>use Rack::AddressMunging, strategy: :hex</code>
16
+ class AddressMunging
17
+ autoload :Strategy, 'rack/address_munging/strategy'
18
+ autoload :Detection, 'rack/address_munging/detection'
19
+
20
+ attr_reader :strategy
21
+
22
+ def initialize(app, options = {})
23
+ @app = app
24
+ @options = { strategy: :Hex }.merge(options)
25
+ @strategy = Strategy.const_get(@options[:strategy]).new
26
+ end
27
+
28
+ def call(env)
29
+ @status, @headers, @response = @app.call(env)
30
+ mung! if html?
31
+ [@status, @headers, @response]
32
+ end
33
+
34
+ private
35
+
36
+ def html?
37
+ !(@headers['Content-Type'] =~ /html/).nil?
38
+ end
39
+
40
+ def mung!
41
+ @response = Response.new([], @status, @headers).tap do |r|
42
+ @strategy.apply(r, @response)
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'rack/address_munging/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'rack-address_munging'
9
+ spec.version = Rack::AddressMunging::VERSION
10
+ spec.licenses = ['Apache-2.0']
11
+ spec.authors = ['Gaël-Ian Havard']
12
+ spec.email = ['gael-ian@notus.sh']
13
+
14
+ spec.summary = 'Rack middleware for automatic address munging.'
15
+ spec.description = 'A Rack middleware for automatic e-mail addresses munging.'
16
+ spec.homepage = 'https://github.com/notus-sh/rack-address_munging'
17
+
18
+ if spec.respond_to?(:metadata)
19
+ spec.metadata["allowed_push_host"] = 'https://rubygems.org'
20
+ else
21
+ raise "RubyGems 2.0 or newer is required."
22
+ end
23
+
24
+ spec.require_paths = ['lib']
25
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
26
+ f.match(%r{^(test|spec|features)/})
27
+ end
28
+
29
+ spec.add_dependency 'mail', '> 2.5.0'
30
+ spec.add_dependency 'rack', '>= 0.9.1'
31
+
32
+ spec.add_development_dependency 'bundler', '~> 1.16'
33
+ spec.add_development_dependency 'rake', '~> 10.0'
34
+ spec.add_development_dependency 'rspec', '~> 3.7.0'
35
+ spec.add_development_dependency 'rubocop'
36
+ end
metadata ADDED
@@ -0,0 +1,145 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack-address_munging
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Gaël-Ian Havard
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-03-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: mail
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">"
18
+ - !ruby/object:Gem::Version
19
+ version: 2.5.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">"
25
+ - !ruby/object:Gem::Version
26
+ version: 2.5.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: rack
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.9.1
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 0.9.1
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.16'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.16'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 3.7.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 3.7.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop
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
+ description: A Rack middleware for automatic e-mail addresses munging.
98
+ email:
99
+ - gael-ian@notus.sh
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - ".gitignore"
105
+ - ".rspec"
106
+ - ".rubocop.yml"
107
+ - ".travis.yml"
108
+ - Gemfile
109
+ - Gemfile.lock
110
+ - LICENSE
111
+ - README.md
112
+ - Rakefile
113
+ - lib/rack/address_munging.rb
114
+ - lib/rack/address_munging/detection.rb
115
+ - lib/rack/address_munging/strategy.rb
116
+ - lib/rack/address_munging/strategy/hex.rb
117
+ - lib/rack/address_munging/strategy/rot13js.rb
118
+ - lib/rack/address_munging/version.rb
119
+ - rack-address_munging.gemspec
120
+ homepage: https://github.com/notus-sh/rack-address_munging
121
+ licenses:
122
+ - Apache-2.0
123
+ metadata:
124
+ allowed_push_host: https://rubygems.org
125
+ post_install_message:
126
+ rdoc_options: []
127
+ require_paths:
128
+ - lib
129
+ required_ruby_version: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ required_rubygems_version: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ requirements: []
140
+ rubyforge_project:
141
+ rubygems_version: 2.6.14
142
+ signing_key:
143
+ specification_version: 4
144
+ summary: Rack middleware for automatic address munging.
145
+ test_files: []