antispam 0.1.4 → 0.1.7
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 +113 -72
- data/app/controllers/antispam/application_controller.rb +11 -11
- data/app/controllers/antispam/blocks_controller.rb +28 -28
- data/app/controllers/antispam/challenges_controller.rb +50 -49
- data/app/controllers/antispam/clears_controller.rb +28 -28
- data/app/views/antispam/blocks/index.html.erb +38 -38
- data/app/views/antispam/clears/index.html.erb +32 -32
- data/app/views/layouts/antispam/application.html.erb +15 -15
- data/db/migrate/20210131165122_add_threat_to_antispam_blocks.rb +5 -5
- data/lib/antispam/blacklists/httpbl.rb +14 -9
- data/lib/antispam/checker.rb +20 -0
- data/lib/antispam/results.rb +10 -0
- data/lib/antispam/spamcheckers/defendium.rb +29 -0
- data/lib/antispam/tools.rb +57 -48
- data/lib/antispam/version.rb +3 -3
- data/lib/antispam.rb +17 -11
- metadata +22 -11
- data/app/views/antispam/blocks/_form.html.erb +0 -37
- data/app/views/antispam/blocks/edit.html.erb +0 -6
- data/app/views/antispam/blocks/new.html.erb +0 -5
- data/app/views/antispam/clears/_form.html.erb +0 -42
- data/app/views/antispam/clears/edit.html.erb +0 -6
- data/app/views/antispam/clears/new.html.erb +0 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 636c6cfd1e3a5c84182eaa1e19966e553a2098c4f3a01a049cdbe4613165a52e
|
4
|
+
data.tar.gz: 8a53d23ef78da214962bd81411a97a720d5eba3a15817d3f7ccd5bfac81719ec
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b4d6e23e0432af6b62b7cd9e469c2393a9e4f4513b13d93d282e6841062bd706d70fa44dd6bed0d79658da80ff52827ee8ba9d63baa0a84df2112a7fd313b3dd
|
7
|
+
data.tar.gz: 9ca4921062395565e50fa29daf9d56bd3e691b5a675fb34bc4d6ec5e1378da1f3be5b19bdc73294be7fcb55b8e3d766819c140ef45b602d8904818eccf10f187
|
data/README.md
CHANGED
@@ -1,72 +1,113 @@
|
|
1
|
-
# Antispam
|
2
|
-
The antispam gem helps prevent spam in your Rails applications by
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
```
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
##
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
1
|
+
# Antispam
|
2
|
+
The antispam gem helps prevent spam in your Rails applications by
|
3
|
+
providing tools that check spam against powerful spam-prevention
|
4
|
+
databases, accessible for free.
|
5
|
+
|
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 uses the blazing fast Defendium API to quickly determine if submitted
|
9
|
+
content is spam or not.
|
10
|
+
|
11
|
+
The second feature allows you to submit user-provided content to a spam
|
12
|
+
checking service that uses machine learning and a database of content to
|
13
|
+
determine whether the user's submitted content is spam.
|
14
|
+
|
15
|
+
## Spam Content Checking - Usage
|
16
|
+
|
17
|
+
```
|
18
|
+
result = Antispam::Checker.check(content: @comment.body)
|
19
|
+
if result.is_spam?
|
20
|
+
@comment.save
|
21
|
+
else
|
22
|
+
redirect_to "/access_denied"
|
23
|
+
end
|
24
|
+
```
|
25
|
+
|
26
|
+
## Bad IP Checking - Usage
|
27
|
+
|
28
|
+
The gem is used by adding this to your ApplicationController.rb
|
29
|
+
|
30
|
+
```
|
31
|
+
before_action do
|
32
|
+
check_ip_against_database(ip_blacklists: {default: 'yourcodehere'}, verbose: true)
|
33
|
+
end
|
34
|
+
```
|
35
|
+
|
36
|
+
Codes are from the [httpbl](https://www.projecthoneypot.org/httpbl.php) at projecthoneypot.org
|
37
|
+
|
38
|
+
Once the filter is setup, everything else is handled for your application.
|
39
|
+
By default the gem will run during any request that is not a GET request.
|
40
|
+
|
41
|
+
You can change the filter to run during other requests.
|
42
|
+
|
43
|
+
```
|
44
|
+
before_action do
|
45
|
+
check_ip_against_database(ip_blacklists: {default: 'yourcodehere'}, methods: [:get,:post,:put,:patch,:delete])
|
46
|
+
end
|
47
|
+
```
|
48
|
+
|
49
|
+
Blacklist database lookups are cached for 24 hours, and cached results won't need
|
50
|
+
to slowdown your app by additional http requests on the backend.
|
51
|
+
|
52
|
+
The gem needs to create some database tables to function; these store the cached
|
53
|
+
blacklist database lookups, and any actions caused by the gem.
|
54
|
+
|
55
|
+
You need to add this to your routes.rb
|
56
|
+
```
|
57
|
+
mount Antispam::Engine => "/antispam"
|
58
|
+
```
|
59
|
+
You can see what IP addresses have been blocked by going to /antispam/blocks
|
60
|
+
but your ApplicationController.rb must respond to ```is_admin?``` function.
|
61
|
+
|
62
|
+
|
63
|
+
## Installation
|
64
|
+
Add this line to your application's Gemfile:
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
gem 'antispam'
|
68
|
+
```
|
69
|
+
|
70
|
+
And then execute:
|
71
|
+
```bash
|
72
|
+
$ bundle
|
73
|
+
```
|
74
|
+
|
75
|
+
Or install it yourself as:
|
76
|
+
```bash
|
77
|
+
$ gem install antispam
|
78
|
+
$ rails antispam:install:migrations
|
79
|
+
$ rails db:migrate SCOPE=antispam
|
80
|
+
```
|
81
|
+
The gem depends on image_processing, which depends on vips. We are using vips to
|
82
|
+
generate captcha images.
|
83
|
+
```
|
84
|
+
sudo apt install libvips-tools
|
85
|
+
```
|
86
|
+
|
87
|
+
## Development
|
88
|
+
|
89
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
90
|
+
|
91
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
92
|
+
|
93
|
+
## Contributing
|
94
|
+
|
95
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/ryankopf/antispam. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/antispam/blob/master/CODE_OF_CONDUCT.md).
|
96
|
+
|
97
|
+
## License
|
98
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
99
|
+
|
100
|
+
## Code of Conduct
|
101
|
+
|
102
|
+
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).
|
103
|
+
|
104
|
+
## NO WARRANTY
|
105
|
+
|
106
|
+
THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY KIND,
|
107
|
+
EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO,
|
108
|
+
ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS,
|
109
|
+
ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
|
110
|
+
OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE
|
111
|
+
ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO
|
112
|
+
THE SUBJECT SOFTWARE. THIS SOFTWARE IS PROVIDED "AS IS." IF YOUR JURISDICTION
|
113
|
+
DOES NOT ALLOW THESE LIMITATIONS THEN YOU MAY NOT USE THE SOFTWARE.
|
@@ -1,11 +1,11 @@
|
|
1
|
-
module Antispam
|
2
|
-
class ApplicationController < ::ApplicationController
|
3
|
-
def must_be_admin
|
4
|
-
begin
|
5
|
-
render plain: 'Not available.' unless is_admin?
|
6
|
-
rescue
|
7
|
-
render plain: 'Not available.'
|
8
|
-
end
|
9
|
-
end
|
10
|
-
end
|
11
|
-
end
|
1
|
+
module Antispam
|
2
|
+
class ApplicationController < ::ApplicationController
|
3
|
+
def must_be_admin
|
4
|
+
begin
|
5
|
+
render plain: 'Not available.' unless is_admin?
|
6
|
+
rescue
|
7
|
+
render plain: 'Not available.'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -1,28 +1,28 @@
|
|
1
|
-
require_dependency "antispam/application_controller"
|
2
|
-
|
3
|
-
module Antispam
|
4
|
-
class BlocksController < ApplicationController
|
5
|
-
before_action :must_be_admin
|
6
|
-
before_action :set_block, only: [:show]
|
7
|
-
|
8
|
-
# GET /blocks
|
9
|
-
def index
|
10
|
-
@blocks = Block.all
|
11
|
-
end
|
12
|
-
|
13
|
-
# GET /blocks/1
|
14
|
-
def show
|
15
|
-
end
|
16
|
-
|
17
|
-
private
|
18
|
-
# Use callbacks to share common setup or constraints between actions.
|
19
|
-
def set_block
|
20
|
-
@block = Block.find(params[:id])
|
21
|
-
end
|
22
|
-
|
23
|
-
# Only allow a list of trusted parameters through.
|
24
|
-
def block_params
|
25
|
-
params.require(:block).permit(:ip, :provider, :controllername, :actionname)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
1
|
+
require_dependency "antispam/application_controller"
|
2
|
+
|
3
|
+
module Antispam
|
4
|
+
class BlocksController < ApplicationController
|
5
|
+
before_action :must_be_admin
|
6
|
+
before_action :set_block, only: [:show]
|
7
|
+
|
8
|
+
# GET /blocks
|
9
|
+
def index
|
10
|
+
@blocks = Block.all
|
11
|
+
end
|
12
|
+
|
13
|
+
# GET /blocks/1
|
14
|
+
def show
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
# Use callbacks to share common setup or constraints between actions.
|
19
|
+
def set_block
|
20
|
+
@block = Block.find(params[:id])
|
21
|
+
end
|
22
|
+
|
23
|
+
# Only allow a list of trusted parameters through.
|
24
|
+
def block_params
|
25
|
+
params.require(:block).permit(:ip, :provider, :controllername, :actionname)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -1,49 +1,50 @@
|
|
1
|
-
require_dependency "antispam/application_controller"
|
2
|
-
|
3
|
-
module Antispam
|
4
|
-
class ChallengesController < ApplicationController
|
5
|
-
before_action :set_challenge, only: [:show, :edit, :update, :destroy]
|
6
|
-
|
7
|
-
# GET /challenges/1
|
8
|
-
def show
|
9
|
-
respond_to do |format|
|
10
|
-
format.jpeg do
|
11
|
-
image = @challenge.get_image
|
12
|
-
render content_type: 'image/jpeg', plain: image.jpegsave_buffer
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
# GET /challenges/new
|
18
|
-
def new
|
19
|
-
# use in the future for changing code
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
a.
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
end
|
1
|
+
require_dependency "antispam/application_controller"
|
2
|
+
|
3
|
+
module Antispam
|
4
|
+
class ChallengesController < ApplicationController
|
5
|
+
before_action :set_challenge, only: [:show, :edit, :update, :destroy]
|
6
|
+
|
7
|
+
# GET /challenges/1
|
8
|
+
def show
|
9
|
+
respond_to do |format|
|
10
|
+
format.jpeg do
|
11
|
+
image = @challenge.get_image
|
12
|
+
render content_type: 'image/jpeg', plain: image.jpegsave_buffer
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# GET /challenges/new
|
18
|
+
def new
|
19
|
+
# use in the future for changing code
|
20
|
+
head :ok
|
21
|
+
end
|
22
|
+
|
23
|
+
# PATCH/PUT /challenges/1
|
24
|
+
def update
|
25
|
+
if @challenge.validate?(params[:challenge][:answer])
|
26
|
+
a = Antispam::Ip.find_or_create_by(address: request.remote_ip, provider: 'httpbl')
|
27
|
+
before = a.threat
|
28
|
+
a.threat = [(a.threat || 0) - 25, 0].max
|
29
|
+
c = Clear.create(ip: request.remote_ip, answer: params[:challenge][:answer], result: 'Passed', threat_before: before, threat_after: a.threat)
|
30
|
+
a.expires_at = 1.hour.from_now
|
31
|
+
a.save
|
32
|
+
redirect_to '/'
|
33
|
+
else
|
34
|
+
c = Clear.create(ip: request.remote_ip, answer: params[:challenge][:answer], result: 'Failed')
|
35
|
+
redirect_to '/antispam/validate', notice: 'Invalid answer.'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
# Use callbacks to share common setup or constraints between actions.
|
41
|
+
def set_challenge
|
42
|
+
@challenge = Challenge.find(params[:id])
|
43
|
+
end
|
44
|
+
|
45
|
+
# Only allow a list of trusted parameters through.
|
46
|
+
def challenge_params
|
47
|
+
params.require(:challenge).permit(:answer, :code)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -1,28 +1,28 @@
|
|
1
|
-
require_dependency "antispam/application_controller"
|
2
|
-
|
3
|
-
module Antispam
|
4
|
-
class ClearsController < ApplicationController
|
5
|
-
before_action :must_be_admin
|
6
|
-
before_action :set_clear, only: [:show, :edit, :update, :destroy]
|
7
|
-
|
8
|
-
# GET /clears
|
9
|
-
def index
|
10
|
-
@clears = Clear.all
|
11
|
-
end
|
12
|
-
|
13
|
-
# GET /clears/1
|
14
|
-
def show
|
15
|
-
end
|
16
|
-
|
17
|
-
private
|
18
|
-
# Use callbacks to share common setup or constraints between actions.
|
19
|
-
def set_clear
|
20
|
-
@clear = Clear.find(params[:id])
|
21
|
-
end
|
22
|
-
|
23
|
-
# Only allow a list of trusted parameters through.
|
24
|
-
def clear_params
|
25
|
-
params.require(:clear).permit(:ip, :result, :answer, :threat_before, :threat_after)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
1
|
+
require_dependency "antispam/application_controller"
|
2
|
+
|
3
|
+
module Antispam
|
4
|
+
class ClearsController < ApplicationController
|
5
|
+
before_action :must_be_admin
|
6
|
+
before_action :set_clear, only: [:show, :edit, :update, :destroy]
|
7
|
+
|
8
|
+
# GET /clears
|
9
|
+
def index
|
10
|
+
@clears = Clear.all
|
11
|
+
end
|
12
|
+
|
13
|
+
# GET /clears/1
|
14
|
+
def show
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
# Use callbacks to share common setup or constraints between actions.
|
19
|
+
def set_clear
|
20
|
+
@clear = Clear.find(params[:id])
|
21
|
+
end
|
22
|
+
|
23
|
+
# Only allow a list of trusted parameters through.
|
24
|
+
def clear_params
|
25
|
+
params.require(:clear).permit(:ip, :result, :answer, :threat_before, :threat_after)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -1,39 +1,39 @@
|
|
1
|
-
<p id="notice"><%= notice %></p>
|
2
|
-
|
3
|
-
<div class="row">
|
4
|
-
<div class="cx">
|
5
|
-
<h1>Blocks</h1>
|
6
|
-
|
7
|
-
<table>
|
8
|
-
<thead>
|
9
|
-
<tr>
|
10
|
-
<th>Ip</th>
|
11
|
-
<th>Provider</th>
|
12
|
-
<th>Controllername</th>
|
13
|
-
<th>Actionname</th>
|
14
|
-
<th>Threat</th>
|
15
|
-
<th colspan="3"></th>
|
16
|
-
</tr>
|
17
|
-
</thead>
|
18
|
-
|
19
|
-
<tbody>
|
20
|
-
<% Antispam::Block.all.order(created_at: :desc).limit(50).each do |block| %>
|
21
|
-
<tr>
|
22
|
-
<td><%= block.ip %></td>
|
23
|
-
<td><%= block.provider %></td>
|
24
|
-
<td><%= block.controllername %></td>
|
25
|
-
<td><%= block.actionname %></td>
|
26
|
-
<td><%= block.threat %></td>
|
27
|
-
<td><%= time_ago_in_words block.created_at %> ago</td>
|
28
|
-
<!-- <td><%#= link_to 'Show', block %></td>-->
|
29
|
-
<!-- <td><%#= link_to 'Edit', edit_block_path(block) %></td>-->
|
30
|
-
<!-- <td><%#= link_to 'Destroy', block, method: :delete, data: { confirm: 'Are you sure?' } %></td>-->
|
31
|
-
</tr>
|
32
|
-
<% end %>
|
33
|
-
</tbody>
|
34
|
-
</table>
|
35
|
-
</div>
|
36
|
-
<div class="cx">
|
37
|
-
<%= render template: '/antispam/clears/index
|
38
|
-
</div>
|
1
|
+
<p id="notice"><%= notice %></p>
|
2
|
+
|
3
|
+
<div class="row">
|
4
|
+
<div class="cx">
|
5
|
+
<h1>Blocks</h1>
|
6
|
+
|
7
|
+
<table>
|
8
|
+
<thead>
|
9
|
+
<tr>
|
10
|
+
<th>Ip</th>
|
11
|
+
<th>Provider</th>
|
12
|
+
<th>Controllername</th>
|
13
|
+
<th>Actionname</th>
|
14
|
+
<th>Threat</th>
|
15
|
+
<th colspan="3"></th>
|
16
|
+
</tr>
|
17
|
+
</thead>
|
18
|
+
|
19
|
+
<tbody>
|
20
|
+
<% Antispam::Block.all.order(created_at: :desc).limit(50).each do |block| %>
|
21
|
+
<tr>
|
22
|
+
<td><%= block.ip %></td>
|
23
|
+
<td><%= block.provider %></td>
|
24
|
+
<td><%= block.controllername %></td>
|
25
|
+
<td><%= block.actionname %></td>
|
26
|
+
<td><%= block.threat %></td>
|
27
|
+
<td><%= time_ago_in_words block.created_at %> ago</td>
|
28
|
+
<!-- <td><%#= link_to 'Show', block %></td>-->
|
29
|
+
<!-- <td><%#= link_to 'Edit', edit_block_path(block) %></td>-->
|
30
|
+
<!-- <td><%#= link_to 'Destroy', block, method: :delete, data: { confirm: 'Are you sure?' } %></td>-->
|
31
|
+
</tr>
|
32
|
+
<% end %>
|
33
|
+
</tbody>
|
34
|
+
</table>
|
35
|
+
</div>
|
36
|
+
<div class="cx">
|
37
|
+
<%= render template: '/antispam/clears/index', formats: :html %>
|
38
|
+
</div>
|
39
39
|
</div>
|
@@ -1,32 +1,32 @@
|
|
1
|
-
<p id="notice"><%= notice %></p>
|
2
|
-
|
3
|
-
<h1>Clears</h1>
|
4
|
-
|
5
|
-
<table>
|
6
|
-
<thead>
|
7
|
-
<tr>
|
8
|
-
<th>Ip</th>
|
9
|
-
<th>Result</th>
|
10
|
-
<th>Answer</th>
|
11
|
-
<th>Threat before</th>
|
12
|
-
<th>Threat after</th>
|
13
|
-
<th colspan="3"></th>
|
14
|
-
</tr>
|
15
|
-
</thead>
|
16
|
-
|
17
|
-
<tbody>
|
18
|
-
<% Antispam::Clear.all.order(created_at: :desc).limit(50).each do |clear| %>
|
19
|
-
<tr>
|
20
|
-
<td><%= clear.ip %></td>
|
21
|
-
<td><%= clear.result %></td>
|
22
|
-
<td><%= clear.answer %></td>
|
23
|
-
<td><%= clear.threat_before %></td>
|
24
|
-
<td><%= clear.threat_after %></td>
|
25
|
-
<td><%= time_ago_in_words clear.created_at %> ago</td>
|
26
|
-
<!-- <td><%#= link_to 'Show', clear %></td>-->
|
27
|
-
<!-- <td><%#= link_to 'Edit', edit_clear_path(clear) %></td>-->
|
28
|
-
<!-- <td><%#= link_to 'Destroy', clear, method: :delete, data: { confirm: 'Are you sure?' } %></td>-->
|
29
|
-
</tr>
|
30
|
-
<% end %>
|
31
|
-
</tbody>
|
32
|
-
</table>
|
1
|
+
<p id="notice"><%= notice %></p>
|
2
|
+
|
3
|
+
<h1>Clears</h1>
|
4
|
+
|
5
|
+
<table>
|
6
|
+
<thead>
|
7
|
+
<tr>
|
8
|
+
<th>Ip</th>
|
9
|
+
<th>Result</th>
|
10
|
+
<th>Answer</th>
|
11
|
+
<th>Threat before</th>
|
12
|
+
<th>Threat after</th>
|
13
|
+
<th colspan="3"></th>
|
14
|
+
</tr>
|
15
|
+
</thead>
|
16
|
+
|
17
|
+
<tbody>
|
18
|
+
<% Antispam::Clear.all.order(created_at: :desc).limit(50).each do |clear| %>
|
19
|
+
<tr>
|
20
|
+
<td><%= clear.ip %></td>
|
21
|
+
<td><%= clear.result %></td>
|
22
|
+
<td><%= clear.answer %></td>
|
23
|
+
<td><%= clear.threat_before %></td>
|
24
|
+
<td><%= clear.threat_after %></td>
|
25
|
+
<td><%= time_ago_in_words clear.created_at %> ago</td>
|
26
|
+
<!-- <td><%#= link_to 'Show', clear %></td>-->
|
27
|
+
<!-- <td><%#= link_to 'Edit', edit_clear_path(clear) %></td>-->
|
28
|
+
<!-- <td><%#= link_to 'Destroy', clear, method: :delete, data: { confirm: 'Are you sure?' } %></td>-->
|
29
|
+
</tr>
|
30
|
+
<% end %>
|
31
|
+
</tbody>
|
32
|
+
</table>
|
@@ -1,15 +1,15 @@
|
|
1
|
-
<!DOCTYPE html>
|
2
|
-
<html>
|
3
|
-
<head>
|
4
|
-
<title>Antispam</title>
|
5
|
-
<%= csrf_meta_tags %>
|
6
|
-
<%= csp_meta_tag %>
|
7
|
-
<style>.row { width:100%;display: flex;} .cx { width: 50%; }</style>
|
8
|
-
<%#= stylesheet_link_tag "antispam/application", media: "all" %>
|
9
|
-
</head>
|
10
|
-
<body>
|
11
|
-
|
12
|
-
<%= yield %>
|
13
|
-
|
14
|
-
</body>
|
15
|
-
</html>
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>Antispam</title>
|
5
|
+
<%= csrf_meta_tags %>
|
6
|
+
<%= csp_meta_tag %>
|
7
|
+
<style>.row { width:100%;display: flex;} .cx { width: 50%; }</style>
|
8
|
+
<%#= stylesheet_link_tag "antispam/application", media: "all" %>
|
9
|
+
</head>
|
10
|
+
<body>
|
11
|
+
|
12
|
+
<%= yield %>
|
13
|
+
|
14
|
+
</body>
|
15
|
+
</html>
|
@@ -1,5 +1,5 @@
|
|
1
|
-
class AddThreatToAntispamBlocks < ActiveRecord::Migration[6.1]
|
2
|
-
def change
|
3
|
-
add_column :antispam_blocks, :threat, :integer
|
4
|
-
end
|
5
|
-
end
|
1
|
+
class AddThreatToAntispamBlocks < ActiveRecord::Migration[6.1]
|
2
|
+
def change
|
3
|
+
add_column :antispam_blocks, :threat, :integer
|
4
|
+
end
|
5
|
+
end
|
@@ -2,28 +2,33 @@ require 'resolv'
|
|
2
2
|
module Antispam
|
3
3
|
module Blacklists
|
4
4
|
class Httpbl
|
5
|
-
def self.check(ip, key)
|
5
|
+
def self.check(ip, key, verbose)
|
6
6
|
threat = 0
|
7
7
|
begin
|
8
|
-
|
8
|
+
old_result = get_old_result(ip)
|
9
|
+
if old_result
|
10
|
+
Rails.logger.info "Returning old result for #{ip}." if verbose
|
11
|
+
return get_old_result(ip)
|
12
|
+
end
|
9
13
|
check = ip.split('.').reverse.join('.')
|
10
14
|
host = key + '.' + check + ".dnsbl.httpbl.org"
|
11
15
|
address = Resolv::getaddress(host)
|
12
16
|
z,days,threat,iptype = address.split('.')
|
13
|
-
Rails.logger.info "Spam located: #{iptype} type at #{threat} threat. (#{ip} - #{address})"
|
17
|
+
Rails.logger.info "Spam located: #{iptype} type at #{threat} threat. (#{ip} - #{address})" if verbose
|
18
|
+
threat = threat.to_i
|
14
19
|
# Create or update
|
15
|
-
if (threat
|
16
|
-
Rails.logger.info "Spamcheck: Very high, over 30!"
|
20
|
+
if (threat > 30)
|
21
|
+
Rails.logger.info "Spamcheck: Very high, over 30!" if verbose
|
17
22
|
end
|
18
23
|
rescue Exception => e
|
19
24
|
case e
|
20
25
|
when Resolv::ResolvError #Not spam! This blacklist gives an error when there's no spam threat.
|
21
|
-
Rails.logger.info "Spamcheck: OK! Resolve error means the httpbl does not consider this spam."
|
26
|
+
Rails.logger.info "Spamcheck: OK! Resolve error means the httpbl does not consider this spam." if verbose
|
22
27
|
when Interrupt #Something broke while trying to check blacklist.
|
23
|
-
Rails.logger.info "Spamcheck: Interrupt when trying to resolve http blacklist. Possible timeout?"
|
28
|
+
Rails.logger.info "Spamcheck: Interrupt when trying to resolve http blacklist. Possible timeout?" if verbose
|
24
29
|
else # Time Out
|
25
|
-
Rails.logger.info "Spamcheck: There was an error, possibly a time out, when checking this IP."
|
26
|
-
Rails.logger.info e.to_s
|
30
|
+
Rails.logger.info "Spamcheck: There was an error, possibly a time out, when checking this IP." if verbose
|
31
|
+
Rails.logger.info e.to_s if verbose
|
27
32
|
end
|
28
33
|
end
|
29
34
|
update_old_result(ip, threat)
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Antispam
|
2
|
+
module Checker
|
3
|
+
# Checks content for spam
|
4
|
+
# check(options, spamcheck_providers)
|
5
|
+
# Usage: check({content: "No spam here"}, {defendium: 'MY_API_KEY'}})
|
6
|
+
def self.check(options = {}, spamcheck_providers = {defendium: 'YOUR_KEY'})
|
7
|
+
Rails.logger.info "Content was nil for spamcheck." if options[:content].nil? && options[:verbose]
|
8
|
+
return if options[:content].nil?
|
9
|
+
Rails.logger.info "Spamcheckers should be a hash" if (!(options[:spamcheck_providers].is_a? Hash)) && options[:verbose]
|
10
|
+
results = []
|
11
|
+
spamcheck_providers.each do |spamchecker_name, spamchecker_api_key|
|
12
|
+
if spamchecker_name == :defendium
|
13
|
+
results.append Antispam::Spamcheckers::Defendium.check(options[:content], spamchecker_api_key, options[:verbose])
|
14
|
+
end
|
15
|
+
end
|
16
|
+
result = Antispam::SpamcheckResult.new(results)
|
17
|
+
return result
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
#require 'resolv'
|
2
|
+
module Antispam
|
3
|
+
module Spamcheckers
|
4
|
+
class Defendium
|
5
|
+
def self.check(content, key, verbose)
|
6
|
+
# nethttp2.rb
|
7
|
+
require 'uri'
|
8
|
+
require 'net/http'
|
9
|
+
|
10
|
+
uri = URI('https://api.defendium.com/check')
|
11
|
+
params = { secret_key: key, content: content }
|
12
|
+
uri.query = URI.encode_www_form(params)
|
13
|
+
|
14
|
+
res = Net::HTTP.get_response(uri)
|
15
|
+
if res.is_a?(Net::HTTPSuccess)
|
16
|
+
result = res.body.to_json
|
17
|
+
if result["warnings"]
|
18
|
+
Rails.logger.info result["warnings"]
|
19
|
+
end
|
20
|
+
if result["result"]
|
21
|
+
return 1
|
22
|
+
else
|
23
|
+
return 0
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/antispam/tools.rb
CHANGED
@@ -1,48 +1,57 @@
|
|
1
|
-
module Antispam
|
2
|
-
module Tools
|
3
|
-
#
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
if options[:
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
1
|
+
module Antispam
|
2
|
+
module Tools
|
3
|
+
# Checks spam against an IP database of spammers.
|
4
|
+
# Usage: before_action :check_ip_against_database
|
5
|
+
def check_ip_against_database(options = {ip_blacklists: {default: ''}})
|
6
|
+
if (options[:methods])
|
7
|
+
return if request.get? unless options[:methods].include?(:get)
|
8
|
+
return if request.post? unless options[:methods].include?(:post)
|
9
|
+
return if request.put? unless options[:methods].include?(:put)
|
10
|
+
return if request.patch? unless options[:methods].include?(:patch)
|
11
|
+
return if request.delete? unless options[:methods].include?(:delete)
|
12
|
+
else
|
13
|
+
return if request.get?
|
14
|
+
end
|
15
|
+
return if skip_if_user_whitelisted
|
16
|
+
return if controller_name == "validate"
|
17
|
+
ip = request.remote_ip
|
18
|
+
# First, check IP blacklists.
|
19
|
+
if (options[:ip_blacklists])
|
20
|
+
if options[:ip_blacklists][:default]
|
21
|
+
options[:ip_blacklists][:httpbl] = options[:ip_blacklists][:default]
|
22
|
+
options[:ip_blacklists].delete(:default)
|
23
|
+
end
|
24
|
+
check_ip_against_blacklists(ip, options[:ip_blacklists], options[:verbose])
|
25
|
+
end
|
26
|
+
# Second, check for weird countries.
|
27
|
+
if (options[:scrutinize_countries_except])
|
28
|
+
|
29
|
+
end
|
30
|
+
Rails.logger.info "Completed IP database check. #{ip}" if options[:verbose]
|
31
|
+
end
|
32
|
+
# Checks the specific blacklists
|
33
|
+
def check_ip_against_blacklists(ip, lists, verbose)
|
34
|
+
lists.each do |provider_name, provider_api_key|
|
35
|
+
Rails.logger.info "Checking provider: #{provider_name}" if verbose
|
36
|
+
if provider_name == :httpbl
|
37
|
+
result = Antispam::Blacklists::Httpbl.check(ip, provider_api_key, verbose)
|
38
|
+
Rails.logger.info(result) if verbose
|
39
|
+
if (result > 30)
|
40
|
+
Block.create(ip: ip, provider: provider_name, threat: result)
|
41
|
+
redirect_to '/antispam/validate'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def skip_if_user_whitelisted
|
48
|
+
if respond_to? :current_user
|
49
|
+
if current_user && current_user.respond_to?(:antispam_whitelisted?)
|
50
|
+
return true if current_user.antispam_whitelisted?
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
data/lib/antispam/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
module Antispam
|
2
|
-
VERSION = '0.1.
|
3
|
-
end
|
1
|
+
module Antispam
|
2
|
+
VERSION = '0.1.7'
|
3
|
+
end
|
data/lib/antispam.rb
CHANGED
@@ -1,11 +1,17 @@
|
|
1
|
-
require "antispam/version"
|
2
|
-
require "antispam/engine"
|
3
|
-
require "antispam/tools"
|
4
|
-
require "antispam/
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
1
|
+
require "antispam/version"
|
2
|
+
require "antispam/engine"
|
3
|
+
require "antispam/tools"
|
4
|
+
require "antispam/checker"
|
5
|
+
require "antispam/blacklists/httpbl"
|
6
|
+
require "antispam/spamcheckers/defendium"
|
7
|
+
require "antispam/results"
|
8
|
+
|
9
|
+
module Antispam
|
10
|
+
ActiveSupport.on_load(:action_controller) do
|
11
|
+
# self refers to ActionController::Base here
|
12
|
+
# This way is removed because below may be more compatible.
|
13
|
+
# self.include Antispam::Tools
|
14
|
+
# Would the below be a better (clearer? more compatible?) way to do this?
|
15
|
+
ActionController::Base.send(:include, Antispam::Tools)
|
16
|
+
end
|
17
|
+
end
|
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.
|
4
|
+
version: 0.1.7
|
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
|
@@ -83,20 +97,14 @@ files:
|
|
83
97
|
- app/models/antispam/challenge.rb
|
84
98
|
- app/models/antispam/clear.rb
|
85
99
|
- app/models/antispam/ip.rb
|
86
|
-
- app/views/antispam/blocks/_form.html.erb
|
87
|
-
- app/views/antispam/blocks/edit.html.erb
|
88
100
|
- app/views/antispam/blocks/index.html.erb
|
89
|
-
- app/views/antispam/blocks/new.html.erb
|
90
101
|
- app/views/antispam/blocks/show.html.erb
|
91
102
|
- app/views/antispam/challenges/_form.html.erb
|
92
103
|
- app/views/antispam/challenges/edit.html.erb
|
93
104
|
- app/views/antispam/challenges/index.html.erb
|
94
105
|
- app/views/antispam/challenges/new.html.erb
|
95
106
|
- app/views/antispam/challenges/show.html.erb
|
96
|
-
- app/views/antispam/clears/_form.html.erb
|
97
|
-
- app/views/antispam/clears/edit.html.erb
|
98
107
|
- app/views/antispam/clears/index.html.erb
|
99
|
-
- app/views/antispam/clears/new.html.erb
|
100
108
|
- app/views/antispam/clears/show.html.erb
|
101
109
|
- app/views/antispam/validate/index.html.erb
|
102
110
|
- app/views/layouts/antispam/application.html.erb
|
@@ -108,7 +116,10 @@ files:
|
|
108
116
|
- db/migrate/20210131165122_add_threat_to_antispam_blocks.rb
|
109
117
|
- lib/antispam.rb
|
110
118
|
- lib/antispam/blacklists/httpbl.rb
|
119
|
+
- lib/antispam/checker.rb
|
111
120
|
- lib/antispam/engine.rb
|
121
|
+
- lib/antispam/results.rb
|
122
|
+
- lib/antispam/spamcheckers/defendium.rb
|
112
123
|
- lib/antispam/tools.rb
|
113
124
|
- lib/antispam/version.rb
|
114
125
|
- lib/tasks/antispam_tasks.rake
|
@@ -135,7 +146,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
135
146
|
- !ruby/object:Gem::Version
|
136
147
|
version: '0'
|
137
148
|
requirements: []
|
138
|
-
rubygems_version: 3.
|
149
|
+
rubygems_version: 3.4.4
|
139
150
|
signing_key:
|
140
151
|
specification_version: 4
|
141
152
|
summary: A spam prevention gem.
|
@@ -1,37 +0,0 @@
|
|
1
|
-
<%= form_with(model: block) do |form| %>
|
2
|
-
<% if block.errors.any? %>
|
3
|
-
<div id="error_explanation">
|
4
|
-
<h2><%= pluralize(block.errors.count, "error") %> prohibited this block from being saved:</h2>
|
5
|
-
|
6
|
-
<ul>
|
7
|
-
<% block.errors.each do |error| %>
|
8
|
-
<li><%= error.full_message %></li>
|
9
|
-
<% end %>
|
10
|
-
</ul>
|
11
|
-
</div>
|
12
|
-
<% end %>
|
13
|
-
|
14
|
-
<div class="field">
|
15
|
-
<%= form.label :ip %>
|
16
|
-
<%= form.text_field :ip %>
|
17
|
-
</div>
|
18
|
-
|
19
|
-
<div class="field">
|
20
|
-
<%= form.label :provider %>
|
21
|
-
<%= form.text_field :provider %>
|
22
|
-
</div>
|
23
|
-
|
24
|
-
<div class="field">
|
25
|
-
<%= form.label :controllername %>
|
26
|
-
<%= form.text_field :controllername %>
|
27
|
-
</div>
|
28
|
-
|
29
|
-
<div class="field">
|
30
|
-
<%= form.label :actionname %>
|
31
|
-
<%= form.text_field :actionname %>
|
32
|
-
</div>
|
33
|
-
|
34
|
-
<div class="actions">
|
35
|
-
<%= form.submit %>
|
36
|
-
</div>
|
37
|
-
<% end %>
|
@@ -1,42 +0,0 @@
|
|
1
|
-
<%= form_with(model: clear) do |form| %>
|
2
|
-
<% if clear.errors.any? %>
|
3
|
-
<div id="error_explanation">
|
4
|
-
<h2><%= pluralize(clear.errors.count, "error") %> prohibited this clear from being saved:</h2>
|
5
|
-
|
6
|
-
<ul>
|
7
|
-
<% clear.errors.each do |error| %>
|
8
|
-
<li><%= error.full_message %></li>
|
9
|
-
<% end %>
|
10
|
-
</ul>
|
11
|
-
</div>
|
12
|
-
<% end %>
|
13
|
-
|
14
|
-
<div class="field">
|
15
|
-
<%= form.label :ip %>
|
16
|
-
<%= form.text_field :ip %>
|
17
|
-
</div>
|
18
|
-
|
19
|
-
<div class="field">
|
20
|
-
<%= form.label :result %>
|
21
|
-
<%= form.text_field :result %>
|
22
|
-
</div>
|
23
|
-
|
24
|
-
<div class="field">
|
25
|
-
<%= form.label :answer %>
|
26
|
-
<%= form.text_field :answer %>
|
27
|
-
</div>
|
28
|
-
|
29
|
-
<div class="field">
|
30
|
-
<%= form.label :threat_before %>
|
31
|
-
<%= form.number_field :threat_before %>
|
32
|
-
</div>
|
33
|
-
|
34
|
-
<div class="field">
|
35
|
-
<%= form.label :threat_after %>
|
36
|
-
<%= form.number_field :threat_after %>
|
37
|
-
</div>
|
38
|
-
|
39
|
-
<div class="actions">
|
40
|
-
<%= form.submit %>
|
41
|
-
</div>
|
42
|
-
<% end %>
|