antispam 0.1.5 → 0.2.0

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: 278c21161c08ebd08f8376df6ddb57fcda33d20d7ae9e9d804a7b3785c23cbae
4
- data.tar.gz: dab176fb46e3d5ecaa6d2c304262adfc4bf612f413b392270e3b44ef03de7147
3
+ metadata.gz: f04775ef37b7cf6a564c81bb3f664dbecf7b638fdf95db9beafd5484e5ceb3e5
4
+ data.tar.gz: bd219f97bc7ff11bf36fe4e98377c0e4b920a93e10f27fa4cae9a170db1d2ab8
5
5
  SHA512:
6
- metadata.gz: 3491eb8c49c91b0cc468440cde3b965ac359d6e3d561e8893a5e48079da0441a2128dd9cb118d30b79e147b8ad79d87ce2df78fcd074217880b1c6f9c4e60748
7
- data.tar.gz: b1d49d286f4bc2d6885e40e7f20b0bd9cdec2f57c608dd443b9c060a8a49ca7799e69f05a0e3e5f422071f385a34fcd39e442a2ee5b5a89f0dfd56425574da5c
6
+ metadata.gz: 18e2653f47965506ef9673c01eb4bc15f1367c253822e8de402f5d1862020b6b60729ae444d03dccb89cf40583263cdef6845bac656512dbc1fb6499596d58cb
7
+ data.tar.gz: 5e19607550a09cc727785ae31fd0bc4221944f2a1a14e2573a43ea4c12969124507e3514dff346d1e8658caf380f2190d0118ced16ef049a3da4c11312126707
data/README.md CHANGED
@@ -1,9 +1,33 @@
1
1
  # Antispam
2
2
  The antispam gem helps prevent spam in your Rails applications by
3
- checking against various antispam blacklists on the web.
4
- You can configure which spam blacklists are checked in your application configuration.
3
+ providing tools that check spam against powerful spam-prevention
4
+ databases, accessible for free.
5
5
 
6
- ## Usage
6
+ The first feature checks against an IP database of spam, allowing you
7
+ to stop spammers who are prolific and have been detected on other websites.
8
+ It relies on the lightning-quick httpbl from Project Honey Pot.
9
+
10
+ The second feature allows you to submit user-provided content to a spam
11
+ checking service that uses machine learning and a database of content to
12
+ determine whether the user's submitted content is spam. It uses the blazing
13
+ fast Defendium API I created to quickly determine if submitted content is
14
+ spam or not. Defendium's [pricing](https://defendium.com/pricing) is free
15
+ for up to 1,000 API calls per day, which should be sufficient for 99% of users.
16
+
17
+ The two features are optional, and you can use either one without the other.
18
+
19
+ ## Spam Content Checking - Usage
20
+
21
+ ```
22
+ result = Antispam::Checker.check(content: @comment.body)
23
+ if result.is_spam?
24
+ redirect_to "/access_denied"
25
+ else
26
+ @comment.save
27
+ end
28
+ ```
29
+
30
+ ## Bad IP Checking - Usage
7
31
 
8
32
  The gem is used by adding this to your ApplicationController.rb
9
33
 
@@ -13,8 +37,29 @@ before_action do
13
37
  end
14
38
  ```
15
39
 
40
+ Codes are from the [httpbl](https://www.projecthoneypot.org/httpbl.php) at projecthoneypot.org
41
+
16
42
  Once the filter is setup, everything else is handled for your application.
17
- The gem will run during any request that is not a GET request.
43
+ By default the gem will run during any request that is not a GET request.
44
+
45
+ When a POST/PATCH/ETC (non-GET) request comes in, the IP blacklist is checked
46
+ to see if the poster is on a spam blacklist. If the poster is on the blacklist
47
+ then the request is automatically blocked and redirected to a captcha page. A
48
+ real user can then enter the captcha to bypass the block. In the future other
49
+ captcha options may be supported, such as mechanical (hashing) captcha and
50
+ other types of invisible captcha.
51
+
52
+ Eventually configurable settings may be in place to give other options when
53
+ a spammy IP is detected, but the current defaults are set to only block spam
54
+ in cases where the blacklist is quite certain the IP is only doing spam.
55
+
56
+ You can change the filter to run during other requests.
57
+
58
+ ```
59
+ before_action do
60
+ check_ip_against_database(ip_blacklists: {default: 'yourcodehere'}, methods: [:get,:post,:put,:patch,:delete])
61
+ end
62
+ ```
18
63
 
19
64
  Blacklist database lookups are cached for 24 hours, and cached results won't need
20
65
  to slowdown your app by additional http requests on the backend.
@@ -27,7 +72,7 @@ You need to add this to your routes.rb
27
72
  mount Antispam::Engine => "/antispam"
28
73
  ```
29
74
  You can see what IP addresses have been blocked by going to /antispam/blocks
30
- but your applicationcontroller must respond to ```is_admin?``` function.
75
+ but your ApplicationController.rb must respond to ```is_admin?``` function.
31
76
 
32
77
 
33
78
  ## Installation
@@ -70,3 +115,14 @@ The gem is available as open source under the terms of the [MIT License](https:/
70
115
  ## Code of Conduct
71
116
 
72
117
  Everyone interacting in the Antispam project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/ryankopf/antispam/blob/master/CODE_OF_CONDUCT.md).
118
+
119
+ ## NO WARRANTY
120
+
121
+ THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY KIND,
122
+ EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO,
123
+ ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS,
124
+ ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
125
+ OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE
126
+ ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO
127
+ THE SUBJECT SOFTWARE. THIS SOFTWARE IS PROVIDED "AS IS." IF YOUR JURISDICTION
128
+ DOES NOT ALLOW THESE LIMITATIONS THEN YOU MAY NOT USE THE SOFTWARE.
@@ -17,6 +17,7 @@ module Antispam
17
17
  # GET /challenges/new
18
18
  def new
19
19
  # use in the future for changing code
20
+ head :ok
20
21
  end
21
22
 
22
23
  # PATCH/PUT /challenges/1
@@ -34,6 +34,6 @@
34
34
  </table>
35
35
  </div>
36
36
  <div class="cx">
37
- <%= render template: '/antispam/clears/index.html' %>
37
+ <%= render template: '/antispam/clears/index', formats: :html %>
38
38
  </div>
39
39
  </div>
@@ -2,6 +2,7 @@ require 'resolv'
2
2
  module Antispam
3
3
  module Blacklists
4
4
  class Httpbl
5
+ # Returns a threat-level number, or 0 if no threat / no result.
5
6
  def self.check(ip, key, verbose)
6
7
  threat = 0
7
8
  begin
@@ -15,19 +16,20 @@ module Antispam
15
16
  address = Resolv::getaddress(host)
16
17
  z,days,threat,iptype = address.split('.')
17
18
  Rails.logger.info "Spam located: #{iptype} type at #{threat} threat. (#{ip} - #{address})" if verbose
19
+ threat = threat.to_i
18
20
  # Create or update
19
- if (threat.to_i > 30)
20
- Rails.logger.info "Spamcheck: Very high, over 30!"
21
+ if (threat > 30)
22
+ Rails.logger.info "Spamcheck: Very high, over 30!" if verbose
21
23
  end
22
24
  rescue Exception => e
23
25
  case e
24
26
  when Resolv::ResolvError #Not spam! This blacklist gives an error when there's no spam threat.
25
- Rails.logger.info "Spamcheck: OK! Resolve error means the httpbl does not consider this spam."
27
+ Rails.logger.info "Spamcheck: OK! Resolve error means the httpbl does not consider this spam." if verbose
26
28
  when Interrupt #Something broke while trying to check blacklist.
27
- Rails.logger.info "Spamcheck: Interrupt when trying to resolve http blacklist. Possible timeout?"
29
+ Rails.logger.info "Spamcheck: Interrupt when trying to resolve http blacklist. Possible timeout?" if verbose
28
30
  else # Time Out
29
- Rails.logger.info "Spamcheck: There was an error, possibly a time out, when checking this IP."
30
- Rails.logger.info e.to_s
31
+ Rails.logger.info "Spamcheck: There was an error, possibly a time out, when checking this IP." if verbose
32
+ Rails.logger.info e.to_s if verbose
31
33
  end
32
34
  end
33
35
  update_old_result(ip, threat)
@@ -0,0 +1,31 @@
1
+ module Antispam
2
+ module Checker
3
+ # Checks content for spam
4
+ # check(options)
5
+ # Usage: check({content: "No spam here", providers: { defendium: 'MY_API_KEY'}})
6
+ def self.check(options = {})
7
+ # Default provider. 'YOUR_KEY' works temporarily, giving a warning but also giving results
8
+ # eventually add something to tell users to add their own keys
9
+ # or choose their preferred provider, when more provider options are added.
10
+ options[:providers] ||= {defendium: 'YOUR_KEY'}
11
+ Rails.logger.info "Content was nil for spamcheck." if options[:content].nil? && options[:verbose]
12
+ return if options[:content].nil?
13
+ Rails.logger.info "Spamcheckers should be a hash" if (!(options[:providers].is_a? Hash)) && options[:verbose]
14
+ results = []
15
+ options[:providers].each do |spamchecker_name, spamchecker_api_key|
16
+ results.append spamchecker(spamchecker_name).check(options[:content], spamchecker_api_key, options[:verbose])
17
+ # if spamchecker_name == :defendium
18
+ # results.append Antispam::Spamcheckers::Defendium.check(options[:content], spamchecker_api_key, options[:verbose])
19
+ # end
20
+ end
21
+ result = Antispam::SpamcheckResult.new(results)
22
+ return result
23
+ end
24
+ def self.spamchecker(provider)
25
+ class_name = provider.to_s.camelize
26
+ raise Antispam::NoSuchSpamcheckerError unless Antispam::Spamcheckers.const_defined? class_name
27
+ Antispam::Spamcheckers.const_get class_name
28
+ end
29
+ end
30
+ class NoSuchSpamcheckerError < StandardError; end
31
+ end
@@ -0,0 +1,18 @@
1
+ module Antispam
2
+ class SpamcheckResult
3
+ def initialize(results)
4
+ @results = results
5
+ end
6
+ def is_spam?
7
+ @results.select{|x| x > 0}.present?
8
+ end
9
+ end
10
+ class BlacklistResult
11
+ def initialize(results)
12
+ @results = results
13
+ end
14
+ def is_bad?
15
+ @results.select{|x| x > 30}.present?
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,30 @@
1
+ #require 'resolv'
2
+ module Antispam
3
+ module Spamcheckers
4
+ class Defendium
5
+ # Returns a boolean, 1 for spam, 0 for not spam.
6
+ def self.check(content, key, verbose)
7
+ # nethttp2.rb
8
+ require 'uri'
9
+ require 'net/http'
10
+
11
+ uri = URI('https://api.defendium.com/check')
12
+ params = { secret_key: key, content: content }
13
+ uri.query = URI.encode_www_form(params)
14
+
15
+ res = Net::HTTP.get_response(uri)
16
+ if res.is_a?(Net::HTTPSuccess)
17
+ result = res.body.to_json
18
+ if result["warnings"]
19
+ Rails.logger.info result["warnings"]
20
+ end
21
+ if result["result"]
22
+ return 1
23
+ else
24
+ return 0
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -1,6 +1,7 @@
1
1
  module Antispam
2
2
  module Tools
3
- # before_action :check_ip_against_database
3
+ # Checks spam against an IP database of spammers.
4
+ # Usage: before_action :check_ip_against_database
4
5
  def check_ip_against_database(options = {ip_blacklists: {default: ''}})
5
6
  if (options[:methods])
6
7
  return if request.get? unless options[:methods].include?(:get)
@@ -28,20 +29,19 @@ module Antispam
28
29
  end
29
30
  Rails.logger.info "Completed IP database check. #{ip}" if options[:verbose]
30
31
  end
32
+ # Checks the specific blacklists
31
33
  def check_ip_against_blacklists(ip, lists, verbose)
34
+ results = []
32
35
  lists.each do |provider_name, provider_api_key|
33
- puts "Checking provider: #{provider_name}" if verbose
34
- if provider_name == :httpbl
35
- result = Antispam::Blacklists::Httpbl.check(ip, provider_api_key, verbose)
36
- Rails.logger.info(result) if verbose
37
- if (result > 30)
38
- Block.create(ip: ip, provider: provider_name, threat: result)
39
- redirect_to '/antispam/validate'
40
- end
41
- end
36
+ Rails.logger.info "Checking provider: #{provider_name}" if verbose
37
+ results.append blacklist(provider_name).check(ip, provider_api_key, verbose)
38
+ end
39
+ result = Antispam::BlacklistResult.new(results)
40
+ if result.is_bad?
41
+ Block.create(ip: ip, provider: lists.keys.first, threat: result)
42
+ redirect_to '/antispam/validate'
42
43
  end
43
44
  end
44
-
45
45
  def skip_if_user_whitelisted
46
46
  if respond_to? :current_user
47
47
  if current_user && current_user.respond_to?(:antispam_whitelisted?)
@@ -49,7 +49,11 @@ module Antispam
49
49
  end
50
50
  end
51
51
  end
52
-
53
-
52
+ def blacklist(provider)
53
+ class_name = provider.to_s.camelize
54
+ raise Antispam::NoSuchBlacklistError unless Antispam::Blacklists.const_defined? class_name
55
+ Antispam::Blacklists.const_get class_name
56
+ end
54
57
  end
58
+ class NoSuchBlacklistError < StandardError; end
55
59
  end
@@ -1,3 +1,3 @@
1
1
  module Antispam
2
- VERSION = '0.1.5'
2
+ VERSION = '0.2.0'
3
3
  end
data/lib/antispam.rb CHANGED
@@ -1,7 +1,10 @@
1
1
  require "antispam/version"
2
2
  require "antispam/engine"
3
3
  require "antispam/tools"
4
+ require "antispam/checker"
4
5
  require "antispam/blacklists/httpbl"
6
+ require "antispam/spamcheckers/defendium"
7
+ require "antispam/results"
5
8
 
6
9
  module Antispam
7
10
  ActiveSupport.on_load(:action_controller) do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: antispam
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Kopf
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-06-26 00:00:00.000000000 Z
11
+ date: 2023-01-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 6.0.0
19
+ version: 6.1.0
20
20
  type: :runtime
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: 6.0.0
26
+ version: 6.1.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: image_processing
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '1.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: net-http
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
41
55
  description: Antispam checks DNS blacklists and helps prevent spam on your site.
42
56
  email:
43
57
  - antispam@ryankopf.com
@@ -102,7 +116,10 @@ files:
102
116
  - db/migrate/20210131165122_add_threat_to_antispam_blocks.rb
103
117
  - lib/antispam.rb
104
118
  - lib/antispam/blacklists/httpbl.rb
119
+ - lib/antispam/checker.rb
105
120
  - lib/antispam/engine.rb
121
+ - lib/antispam/results.rb
122
+ - lib/antispam/spamcheckers/defendium.rb
106
123
  - lib/antispam/tools.rb
107
124
  - lib/antispam/version.rb
108
125
  - lib/tasks/antispam_tasks.rake
@@ -129,7 +146,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
129
146
  - !ruby/object:Gem::Version
130
147
  version: '0'
131
148
  requirements: []
132
- rubygems_version: 3.1.4
149
+ rubygems_version: 3.4.4
133
150
  signing_key:
134
151
  specification_version: 4
135
152
  summary: A spam prevention gem.