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 +4 -4
- data/README.md +61 -5
- data/app/controllers/antispam/challenges_controller.rb +1 -0
- data/app/views/antispam/blocks/index.html.erb +1 -1
- data/lib/antispam/blacklists/httpbl.rb +8 -6
- data/lib/antispam/checker.rb +31 -0
- data/lib/antispam/results.rb +18 -0
- data/lib/antispam/spamcheckers/defendium.rb +30 -0
- data/lib/antispam/tools.rb +17 -13
- data/lib/antispam/version.rb +1 -1
- data/lib/antispam.rb +3 -0
- metadata +22 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f04775ef37b7cf6a564c81bb3f664dbecf7b638fdf95db9beafd5484e5ceb3e5
|
4
|
+
data.tar.gz: bd219f97bc7ff11bf36fe4e98377c0e4b920a93e10f27fa4cae9a170db1d2ab8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
4
|
-
|
3
|
+
providing tools that check spam against powerful spam-prevention
|
4
|
+
databases, accessible for free.
|
5
5
|
|
6
|
-
|
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
|
-
|
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
|
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.
|
@@ -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
|
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
|
data/lib/antispam/tools.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
module Antispam
|
2
2
|
module Tools
|
3
|
-
#
|
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
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
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
|
data/lib/antispam/version.rb
CHANGED
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.
|
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:
|
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.
|
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.
|
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.
|
149
|
+
rubygems_version: 3.4.4
|
133
150
|
signing_key:
|
134
151
|
specification_version: 4
|
135
152
|
summary: A spam prevention gem.
|