antispam 0.2.10 → 0.3.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: 4b9976b110e83413c117ba4e2aadebe3ee782a2e22075b4d005b8ee23f859b6c
4
- data.tar.gz: b103e465db532012980a7a37e01d0b337a11bf58c5182e6951471ee2a344c427
3
+ metadata.gz: b07aedf9f86eeb54b11c0eaa26f5a5dfb46c8b2dffa1dd98458e1762f740a57e
4
+ data.tar.gz: de4475c090684b4b20b0083debbeb39e21a3af2061477b7bb2a962d3497cbb8b
5
5
  SHA512:
6
- metadata.gz: c74852eabd842ab4d54b5dc99cc99224ee40c930d4a1e047a77506c3cc4a6a04bb445c0a92d3946dbdbf81116c1f9334046e4631574af9001b4b13bfee8eebaf
7
- data.tar.gz: 34c5bd57b1db3f574f16a7b467a9e16fb3eb01271a172491eca71d6362f454f8df42cd4c468bfa7059e72466904fbe778f5e26aa7748f29c45bf53820ffb72bf
6
+ metadata.gz: b19aeb03a252ccd582a39d4e9a0c2364f66613b2361c65b2626570856ee44c5a65bfcf33fee5f18e6f3d607ba2768a418012c86eec91425f6086d99e3c4cfe6e
7
+ data.tar.gz: b2b886dcbdb0c2a9587c57a8491e86d872c76713dfb545b3a9cefb72f21384e666aec95241674cadc18307242bdd7ed8a66bf8b1272e550f893809133187cb0d
data/MIT-LICENSE CHANGED
@@ -18,3 +18,8 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
18
  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
19
  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
20
  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ IP DATABASE LICENSE
23
+
24
+ The ip database is from db-ip .com, and is not subject to this license, but
25
+ is CC 4.0 Attribution. https://creativecommons.org/licenses/by/4.0/
data/README.md CHANGED
@@ -84,28 +84,29 @@ gem 'antispam'
84
84
  ```
85
85
 
86
86
  And then execute:
87
- ```bash
88
- $ bundle
89
- ```
90
87
 
91
- Or install it yourself as:
92
88
  ```bash
93
89
  $ gem install antispam
94
90
  $ rails antispam:install:migrations
91
+ $ rails antispam:install
95
92
  $ rails db:migrate SCOPE=antispam
96
93
  ```
94
+
97
95
  The gem depends on image_processing, which depends on vips. We are using vips to
98
96
  generate captcha images.
97
+
99
98
  ```
100
99
  sudo apt install libvips-tools
101
100
  ```
102
101
 
103
- You need to add this to your routes.rb
102
+ To be able to view recent spam-blocking activity, you need to add antispam to your routes.rb
103
+
104
104
  ```
105
105
  mount Antispam::Engine => "/antispam"
106
106
  ```
107
107
 
108
- Then add to your application controller:
108
+ Then add the following to your application controller:
109
+
109
110
  ```
110
111
  before_action do
111
112
  check_ip_against_database(ip_blacklists: {default: 'your_api_key_here'}, verbose: true)
@@ -0,0 +1,10 @@
1
+ require_dependency "antispam/application_controller"
2
+
3
+ module Antispam
4
+ class SignupsController < ApplicationController
5
+ before_action :must_be_admin
6
+ def index
7
+ @signups = Signup.order(created_at: :desc).limit(100).offset(params[:page].to_i * 100)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,40 @@
1
+ module Antispam
2
+ class Iplocator < ApplicationRecord
3
+
4
+ def self.get_country(ip_integer)
5
+ ip = Iplocator.find_by("? > ip_from AND ? < ip_to",ip_integer,ip_integer)
6
+ return nil if ip.nil?
7
+ ip.country_code
8
+ end
9
+
10
+ def self.import
11
+ require 'csv'
12
+ file_path = File.expand_path('../../../../ip-to-country.csv', __FILE__)
13
+ csv_data = CSV.read(file_path, headers: false)
14
+ csv_data.each do |row|
15
+ begin
16
+ Iplocator.create(
17
+ ip_from: IPAddr.new(row[0]).to_i,
18
+ ip_to: IPAddr.new(row[1]).to_i,
19
+ country_code: row[2]
20
+ )
21
+ rescue
22
+ puts "Error importing row: #{row.inspect}"
23
+ end
24
+ end
25
+ puts "Imported #{csv_data.length} rows."
26
+ end
27
+
28
+ def self.ip_to_string(ip)
29
+ ip.split(".").map{|x|x.to_i.to_s(16)}.join("_")
30
+ end
31
+
32
+ def self.countries_suspected_of_spam
33
+ %w[CN IN RU BR ID PH TH VN SG NG UA PK BD EG TR ZA MX MA KE]
34
+ end
35
+ def self.trusted_countries
36
+ %w[US DE GB CA AU JP FR NL]
37
+ end
38
+ end
39
+
40
+ end
@@ -0,0 +1,27 @@
1
+ module Antispam
2
+ class Signup < ApplicationRecord
3
+ def self.analyze(user_id:, ip:)
4
+ ip_integer = IPAddr.new(ip).to_i rescue 0
5
+ signup = Signup.where(user_id: user_id).first_or_initialize
6
+ signup.ip = ip
7
+ signup.country_code = Iplocator.get_country(ip_integer)
8
+ signup.number_from_this_ip = Signup.where(ip: ip).count
9
+ signup.save
10
+ signup.safe?
11
+ end
12
+ def spamscore
13
+ spamscore = 50 # Start at a neutral score
14
+ spamscore += 10 if self.country_code.nil? || (self.country_code == 'ZZ')
15
+ spamscore += 10 if self.number_from_this_ip > 5
16
+ spamscore += 10 if self.number_from_this_ip > 10
17
+ spamscore += 10 if Iplocator.countries_suspected_of_spam.include?(self.country_code)
18
+ spamscore -= 10 if self.number_from_this_ip < 2
19
+ spamscore -= 10 if Iplocator.trusted_countries.include?(self.country_code)
20
+ spamscore = [[spamscore, 0].max, 100].min # Clamp to a value between 0 and 100
21
+ spamscore
22
+ end
23
+ def safe?
24
+ self.spamscore <= 50
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,31 @@
1
+ <p id="notice"><%= notice %></p>
2
+
3
+ <h1>Signups</h1>
4
+
5
+ <table>
6
+ <thead>
7
+ <tr>
8
+ <th>User ID</th>
9
+ <th>IP</th>
10
+ <th>Country Code</th>
11
+ <th>Number from this IP</th>
12
+ <th>Created At</th>
13
+ <th>Updated At</th>
14
+ <th>Safe?</th>
15
+ </tr>
16
+ </thead>
17
+
18
+ <tbody>
19
+ <% @signups.each do |signup| %>
20
+ <tr>
21
+ <td><%= signup.user_id %></td>
22
+ <td><%= signup.ip %></td>
23
+ <td><%= signup.country_code %></td>
24
+ <td><%= signup.number_from_this_ip %></td>
25
+ <td><%= signup.created_at %></td>
26
+ <td><%= signup.updated_at %></td>
27
+ <td><%= signup.safe? %></td>
28
+ </tr>
29
+ <% end %>
30
+ </tbody>
31
+ </table>
data/config/routes.rb CHANGED
@@ -2,6 +2,7 @@ Antispam::Engine.routes.draw do
2
2
  resources :clears
3
3
  resources :blocks
4
4
  resources :challenges
5
+ resources :signups
5
6
  root to: 'ips#index'
6
7
  get 'validate', to: 'validate#index'
7
8
  end
@@ -0,0 +1,58 @@
1
+ class CreateAntispamTables < ActiveRecord::Migration[6.1]
2
+ def change
3
+ create_table :antispam_ips do |t|
4
+ t.string :address
5
+ t.string :provider
6
+ t.integer :threat
7
+ t.datetime :expires_at
8
+
9
+ t.timestamps
10
+ end
11
+
12
+ create_table :antispam_challenges do |t|
13
+ t.string :question
14
+ t.string :answer
15
+ t.string :code
16
+
17
+ t.timestamps
18
+ end
19
+
20
+ create_table :antispam_blocks do |t|
21
+ t.string :ip
22
+ t.string :provider
23
+ t.string :controllername
24
+ t.string :actionname
25
+ t.integer :threat
26
+
27
+ t.timestamps
28
+ end
29
+
30
+ create_table :antispam_clears do |t|
31
+ t.string :ip
32
+ t.string :result
33
+ t.string :answer
34
+ t.integer :threat_before
35
+ t.integer :threat_after
36
+
37
+ t.timestamps
38
+ end
39
+
40
+ create_table :antispam_iplocators do |t|
41
+ t.integer :ip_from, null: false, unsigned: true
42
+ t.integer :ip_to, null: false, unsigned: true
43
+ t.string :country_code, limit: 2, null: false
44
+ t.index ["ip_from", "ip_to"], name: "ips"
45
+ t.index ["ip_from"], name: "ip_from"
46
+ t.index ["ip_to"], name: "ip_to"
47
+ end
48
+
49
+ create table :antispam_signups do |t|
50
+ t.integer :user_id
51
+ t.string :ip
52
+ t.string :country_code
53
+ t.integer :number_from_this_ip
54
+ t.timestamps
55
+ end
56
+
57
+ end
58
+ end
@@ -8,32 +8,31 @@ module Antispam
8
8
  scrutinize_countries_except: nil,
9
9
  verbose: false
10
10
  )
11
- if (options[:methods])
12
- return if request.get? unless options[:methods].include?(:get)
13
- return if request.post? unless options[:methods].include?(:post)
14
- return if request.put? unless options[:methods].include?(:put)
15
- return if request.patch? unless options[:methods].include?(:patch)
16
- return if request.delete? unless options[:methods].include?(:delete)
11
+ if methods
12
+ return if request.get? && !methods.include?(:get)
13
+ return if request.post? && !methods.include?(:post)
14
+ return if request.put? && !methods.include?(:put)
15
+ return if request.patch? && !methods.include?(:patch)
16
+ return if request.delete? && !methods.include?(:delete)
17
17
  else
18
18
  return if request.get?
19
19
  end
20
+
20
21
  return if skip_if_user_whitelisted
21
- return if controller_name.in?["validate","challenges"]
22
+ return if controller_name.in?(%w[validate challenges])
23
+
22
24
  ip = request.remote_ip
23
- # First, check IP blacklists.
24
- if (options[:ip_blacklists])
25
- if options[:ip_blacklists][:default]
26
- options[:ip_blacklists][:httpbl] = options[:ip_blacklists][:default]
27
- options[:ip_blacklists].delete(:default)
28
- end
29
- check_ip_against_blacklists(ip, options[:ip_blacklists], options[:verbose])
30
- end
31
- # Second, check for weird countries.
32
- if (options[:scrutinize_countries_except])
33
-
25
+
26
+ # Handle IP blacklists
27
+ if ip_blacklists
28
+ ip_blacklists[:httpbl] ||= ip_blacklists.delete(:default)
29
+ check_ip_against_blacklists(ip, ip_blacklists, verbose)
34
30
  end
35
- Rails.logger.info "Completed IP database check. #{ip}" if options[:verbose]
36
- end
31
+
32
+ # Country checks, if necessary
33
+ # (expand logic as needed)
34
+ Rails.logger.info "Completed IP database check. #{ip}" if verbose
35
+ end
37
36
  # Checks the specific blacklists
38
37
  def check_ip_against_blacklists(ip, lists, verbose)
39
38
  results = []
@@ -1,3 +1,3 @@
1
1
  module Antispam
2
- VERSION = '0.2.10'
2
+ VERSION = '0.3.0'
3
3
  end
@@ -2,3 +2,11 @@
2
2
  # task :antispam do
3
3
  # # Task goes here
4
4
  # end
5
+
6
+ namespace :antispam do
7
+ desc "Install Antispam by importing IP data"
8
+ task install: :environment do
9
+ Antispam::Iplocator.import
10
+ puts "Antispam IP data imported successfully."
11
+ end
12
+ end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: antispam
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.10
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Kopf
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-10-29 00:00:00.000000000 Z
10
+ date: 2025-02-23 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: rails
@@ -38,6 +37,20 @@ dependencies:
38
37
  - - "~>"
39
38
  - !ruby/object:Gem::Version
40
39
  version: '1.0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: csv
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
41
54
  - !ruby/object:Gem::Dependency
42
55
  name: net-http
43
56
  requirement: !ruby/object:Gem::Requirement
@@ -85,6 +98,7 @@ files:
85
98
  - app/controllers/antispam/blocks_controller.rb
86
99
  - app/controllers/antispam/challenges_controller.rb
87
100
  - app/controllers/antispam/clears_controller.rb
101
+ - app/controllers/antispam/signups_controller.rb
88
102
  - app/controllers/antispam/validate_controller.rb
89
103
  - app/helpers/antispam/application_helper.rb
90
104
  - app/helpers/antispam/blocks_helper.rb
@@ -97,6 +111,8 @@ files:
97
111
  - app/models/antispam/challenge.rb
98
112
  - app/models/antispam/clear.rb
99
113
  - app/models/antispam/ip.rb
114
+ - app/models/antispam/iplocator.rb
115
+ - app/models/antispam/signup.rb
100
116
  - app/views/antispam/blocks/index.html.erb
101
117
  - app/views/antispam/blocks/show.html.erb
102
118
  - app/views/antispam/challenges/_form.html.erb
@@ -106,14 +122,11 @@ files:
106
122
  - app/views/antispam/challenges/show.html.erb
107
123
  - app/views/antispam/clears/index.html.erb
108
124
  - app/views/antispam/clears/show.html.erb
125
+ - app/views/antispam/signups/index.html.erb
109
126
  - app/views/antispam/validate/index.html.erb
110
127
  - app/views/layouts/antispam/application.html.erb
111
128
  - config/routes.rb
112
- - db/migrate/20210130213708_create_antispam_ips.rb
113
- - db/migrate/20210130214835_create_antispam_challenges.rb
114
- - db/migrate/20210130234107_create_antispam_blocks.rb
115
- - db/migrate/20210130235537_create_antispam_clears.rb
116
- - db/migrate/20210131165122_add_threat_to_antispam_blocks.rb
129
+ - db/migrate/20210130213708_create_antispam_tables.rb
117
130
  - lib/antispam.rb
118
131
  - lib/antispam/blacklists/httpbl.rb
119
132
  - lib/antispam/checker.rb
@@ -131,7 +144,6 @@ metadata:
131
144
  homepage_uri: https://ryankopf.com
132
145
  source_code_uri: https://github.com/ryankopf/antispam
133
146
  changelog_uri: https://github.com/ryankopf/antispam/CHANGELOG.md
134
- post_install_message:
135
147
  rdoc_options: []
136
148
  require_paths:
137
149
  - lib
@@ -146,8 +158,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
146
158
  - !ruby/object:Gem::Version
147
159
  version: '0'
148
160
  requirements: []
149
- rubygems_version: 3.5.20
150
- signing_key:
161
+ rubygems_version: 3.6.4
151
162
  specification_version: 4
152
163
  summary: A spam prevention gem.
153
164
  test_files: []
@@ -1,12 +0,0 @@
1
- class CreateAntispamIps < ActiveRecord::Migration[6.1]
2
- def change
3
- create_table :antispam_ips do |t|
4
- t.string :address
5
- t.string :provider
6
- t.integer :threat
7
- t.datetime :expires_at
8
-
9
- t.timestamps
10
- end
11
- end
12
- end
@@ -1,11 +0,0 @@
1
- class CreateAntispamChallenges < ActiveRecord::Migration[6.1]
2
- def change
3
- create_table :antispam_challenges do |t|
4
- t.string :question
5
- t.string :answer
6
- t.string :code
7
-
8
- t.timestamps
9
- end
10
- end
11
- end
@@ -1,12 +0,0 @@
1
- class CreateAntispamBlocks < ActiveRecord::Migration[6.1]
2
- def change
3
- create_table :antispam_blocks do |t|
4
- t.string :ip
5
- t.string :provider
6
- t.string :controllername
7
- t.string :actionname
8
-
9
- t.timestamps
10
- end
11
- end
12
- end
@@ -1,13 +0,0 @@
1
- class CreateAntispamClears < ActiveRecord::Migration[6.1]
2
- def change
3
- create_table :antispam_clears do |t|
4
- t.string :ip
5
- t.string :result
6
- t.string :answer
7
- t.integer :threat_before
8
- t.integer :threat_after
9
-
10
- t.timestamps
11
- end
12
- end
13
- end
@@ -1,5 +0,0 @@
1
- class AddThreatToAntispamBlocks < ActiveRecord::Migration[6.1]
2
- def change
3
- add_column :antispam_blocks, :threat, :integer
4
- end
5
- end