antispam 0.3.2 → 0.3.5

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: 68d9b3db6150451ef0d20a384670ae229cfd9b05cf9200d8cb3dff467a4002db
4
- data.tar.gz: d0e2f8d0b327bda6f2705d9feb27394db86aeb3b44a6994d8b299d9732e066f3
3
+ metadata.gz: bdbea61620fe47180c54c8c12a52980516c45d6ba5a964af6ca10d8e55cafb9a
4
+ data.tar.gz: ab054479f0ff3b244d7bc4a339f464b733267978d4752a80206d47057048770c
5
5
  SHA512:
6
- metadata.gz: 2ce9deb1855e258cb0bb280f02a53c76dc15a5734fd824480da99f178cf8dcb551f59b607d3312ac214a2f6e9bcebdf9767a952aed505837b88b37cc2a39864d
7
- data.tar.gz: 104da28427117f76eb9328c183594d8f9c8d5ab615df7da91879cb0dc8e5cf2017b068df7b90f6c5bdb6c0eee26d3cff219db859aa43af1535360961bfe932c0
6
+ metadata.gz: 070de4332d9749600d1d0cbe1f8b4ac4e3cd8865fc07e9ed6bd0dd1e2c821b62b1034bbd5d6611c8416c65e7a3531d95037cd81072971eaf8bb31abdb92d09d0
7
+ data.tar.gz: 73c95962012c1f57d919992975bb1d55243fde066d2a9e416dc3ec60995bf593d2ad7bebad8998a776f8a3360a2ab054121f20ed6f38919dcb6ac512779c26f4
@@ -1,13 +1,47 @@
1
+ require 'net/http'
1
2
  module Antispam
2
3
  class Signup < ApplicationRecord
3
- def self.analyze(user_id:, ip:)
4
+ def self.analyze(user_id:, ip: nil, request: nil)
5
+ record(user_id: user_id, ip: ip || request&.remote_ip).safe?
6
+ end
7
+ # Like analyze, but also asks Defendium whether the form's _defendium token passed.
8
+ # Returns a hash; :safe is true only if our score is safe and Defendium says "pass".
9
+ def self.check_spam(user_id:, request:)
10
+ signup = record(user_id: user_id, ip: request.remote_ip)
11
+ human_check = verify_human(request)
12
+ {
13
+ safe: signup.safe? && human_check == "pass",
14
+ signup_safe: signup.safe?,
15
+ spamscore: signup.spamscore,
16
+ human_check: human_check,
17
+ country_code: signup.country_code,
18
+ number_from_this_ip: signup.number_from_this_ip
19
+ }
20
+ end
21
+ def self.record(user_id:, ip:)
4
22
  ip_integer = IPAddr.new(ip).to_i rescue 0
5
23
  signup = Signup.where(user_id: user_id).first_or_initialize
6
24
  signup.ip = ip
7
25
  signup.country_code = Iplocator.get_country(ip_integer)
8
26
  signup.number_from_this_ip = Signup.where(ip: ip).count
9
27
  signup.save
10
- signup.safe?
28
+ signup
29
+ end
30
+ # Returns "pass", "uncompleted", "spam", or "unknown" if Defendium couldn't be reached.
31
+ def self.verify_human(request)
32
+ token = request.params[:_defendium]
33
+ return "uncompleted" if token.blank?
34
+ uri = URI("https://defendium.com/human/verify")
35
+ body = { token: token.to_s, host: request.host, ip: request.remote_ip, user_agent: request.user_agent.to_s, required: true, secret_key: defendium_api_key }
36
+ response = Net::HTTP.post(uri, body.to_json, "Content-Type" => "application/json")
37
+ return "unknown" unless response.is_a?(Net::HTTPSuccess)
38
+ JSON.parse(response.body)["result"].to_s.presence || "unknown"
39
+ rescue StandardError
40
+ "unknown"
41
+ end
42
+ # Optional; set in credentials (defendium: api_key:) or ENV["DEFENDIUM_API_KEY"].
43
+ def self.defendium_api_key
44
+ Rails.application.credentials.dig(:defendium, :api_key) || ENV["DEFENDIUM_API_KEY"]
11
45
  end
12
46
  def spamscore
13
47
  spamscore = 50 # Start at a neutral score
@@ -15,13 +49,13 @@ module Antispam
15
49
  spamscore += 10 if self.number_from_this_ip > 5
16
50
  spamscore += 10 if self.number_from_this_ip > 10
17
51
  spamscore += 10 if Iplocator.countries_suspected_of_spam.include?(self.country_code)
18
- spamscore -= 10 if self.number_from_this_ip < 2
52
+ spamscore -= 5 if self.number_from_this_ip < 2
19
53
  spamscore -= 10 if Iplocator.trusted_countries.include?(self.country_code)
20
54
  spamscore = [[spamscore, 0].max, 100].min # Clamp to a value between 0 and 100
21
55
  spamscore
22
56
  end
23
57
  def safe?
24
- self.spamscore <= 50
58
+ self.spamscore < 40
25
59
  end
26
60
  end
27
61
  end
@@ -12,6 +12,7 @@
12
12
  <th>Created At</th>
13
13
  <th>Updated At</th>
14
14
  <th>Safe?</th>
15
+ <th>Spamscore</th>
15
16
  </tr>
16
17
  </thead>
17
18
 
@@ -22,9 +23,10 @@
22
23
  <td><%= signup.ip %></td>
23
24
  <td><%= signup.country_code %></td>
24
25
  <td><%= signup.number_from_this_ip %></td>
25
- <td><%= signup.created_at %></td>
26
- <td><%= signup.updated_at %></td>
26
+ <td><%= signup.created_at.strftime("%Y-%m-%d %I:%M %p") %></td>
27
+ <td><%= signup.updated_at.strftime("%Y-%m-%d %I:%M %p") %></td>
27
28
  <td><%= signup.safe? %></td>
29
+ <td><%= signup.spamscore %></td>
28
30
  </tr>
29
31
  <% end %>
30
32
  </tbody>
@@ -2,11 +2,12 @@
2
2
  module Antispam
3
3
  module Spamcheckers
4
4
  class Defendium
5
- # Returns a boolean, 1 for spam, 0 for not spam.
5
+ # Returns 1 for spam, 0 for not spam.
6
6
  def self.check(content, key, verbose)
7
7
  # nethttp2.rb
8
8
  require 'uri'
9
9
  require 'net/http'
10
+ require 'json'
10
11
 
11
12
  uri = URI('https://api.defendium.com/check')
12
13
  params = { secret_key: key, content: content }
@@ -14,7 +15,7 @@ module Antispam
14
15
 
15
16
  res = Net::HTTP.get_response(uri)
16
17
  if res.is_a?(Net::HTTPSuccess)
17
- result = res.body.to_json
18
+ result = JSON.parse(res.body)
18
19
  if result["warnings"]
19
20
  Rails.logger.info result["warnings"]
20
21
  end
@@ -27,4 +28,4 @@ module Antispam
27
28
  end
28
29
  end
29
30
  end
30
- end
31
+ end
@@ -1,3 +1,3 @@
1
- module Antispam
2
- VERSION = '0.3.2'
3
- end
1
+ module Antispam
2
+ VERSION = '0.3.5'
3
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: antispam
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.3.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Kopf
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-02-23 00:00:00.000000000 Z
10
+ date: 2026-10-23 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: rails
@@ -65,14 +65,13 @@ dependencies:
65
65
  - - ">="
66
66
  - !ruby/object:Gem::Version
67
67
  version: '0'
68
- description: "Antispam helps prevent spam in your Rails applications by checking against
69
- DNS blacklists \nand spam-prevention databases.<br>\n<br>\nKey features:\n- IP-based
70
- spam detection using Project Honey Pot to block known spammers automatically.\n-
71
- Content-based spam detection using Defendium's machine learning API (free for up
72
- to \n 1,000 checks per day).\n- Blacklist lookups are cached for 24 hours to minimize
73
- performance impact.\n\nThe gem integrates seamlessly with Rails, allowing you to
74
- block spam at the request level \nand redirect flagged users to a captcha page.\n\nSee
75
- the README for more details.\n"
68
+ description: 'Antispam helps prevent spam in your Rails applications by checking against
69
+ DNS blacklists and spam-prevention databases. It has two core features: (1) IP-based
70
+ spam detection using Project Honey Pot to block known spammers automatically, and
71
+ (2) content-based spam detection using Defendium’s machine learning API, which is
72
+ free for up to 1,000 checks per day. Blacklist lookups are cached for 24 hours to
73
+ minimize performance impact. The gem integrates seamlessly with Rails, allowing
74
+ you to block spam at the request level and redirect flagged users to a captcha page.'
76
75
  email:
77
76
  - antispam@ryankopf.com
78
77
  executables: []