honeypot_guard 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: a7e5e0d2220ec88464f190b4a9e35b30bf671df65c60d58a95398d91c8028931
4
+ data.tar.gz: 07221aa198dedf7070a0471b0dd5ac5e17abd567d555b5ed6ccb7bd5126c15e8
5
+ SHA512:
6
+ metadata.gz: f51cb80f9a0b0612f3ae1cad02cd791331eaab27658115dbc1903e34cad04dad1b24dd9a3cdc5ab3eccf63cbfb413b2eafefc38b633af1e442731542b8b330e0
7
+ data.tar.gz: 0b44b0aa13811e08f4458a07287b2123475a6840a23a7b76e2a8b39a9a42f5e4b801ba67819b7527de93e3acf12b9d416beb3fc64d9ddb28cda99f5b52a23a23
data/CHANGELOG.md ADDED
@@ -0,0 +1,7 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0
4
+
5
+ - Initial release
6
+ - Adds `spam_trap_fields` view helper
7
+ - Adds `filter_spam` controller before_action
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,56 @@
1
+ # ๐Ÿค Contributing
2
+
3
+ Thanks for your interest in contributing to **HoneypotGuard** ๐Ÿ›ก๏ธ
4
+
5
+ ---
6
+
7
+ ## ๐Ÿงช Use the gem locally
8
+
9
+ To test the gem in a Rails project, add it via a local path.
10
+
11
+ In your Rails app `Gemfile`:
12
+
13
+ ```ruby
14
+ gem "honeypot_guard", path: "../honeypot_guard"
15
+ ```
16
+
17
+ Then run:
18
+
19
+ ```bash
20
+ bundle install
21
+ ```
22
+
23
+ You can now use the gem normally in your views and controllers.
24
+
25
+ ---
26
+
27
+ ## โœ… Run the tests
28
+
29
+ Install dependencies:
30
+
31
+ ```bash
32
+ bundle install
33
+ ```
34
+
35
+ Run the test suite:
36
+
37
+ ```bash
38
+ bundle exec rspec
39
+ ```
40
+
41
+ ### ๐Ÿš† Test against a specific Rails version
42
+
43
+ ```bash
44
+ BUNDLE_GEMFILE=gemfiles/rails_7.2.gemfile bundle exec rspec
45
+ BUNDLE_GEMFILE=gemfiles/rails_8.0.gemfile bundle exec rspec
46
+ ```
47
+
48
+ ---
49
+
50
+ ## ๐Ÿ“ฆ Contributing guidelines
51
+
52
+ - ๐Ÿ” Keep changes small and focused
53
+ - ๐Ÿงช Add tests when changing behavior
54
+ - โœ… Make sure all tests pass before opening a PR
55
+
56
+ Thank you for contributing ๐Ÿ™‚โค๏ธ
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025 OpenCodeForge
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,125 @@
1
+ <h1 align="left">
2
+ ๐Ÿ›ก๏ธ HoneypotGuard
3
+ <a href="https://github.com/OpenCodeForge/honeypot_guard/actions/workflows/ci.yml">
4
+ <img align="right"
5
+ src="https://github.com/OpenCodeForge/honeypot_guard/actions/workflows/ci.yml/badge.svg"
6
+ alt="CI">
7
+ </a>
8
+ </h1>
9
+
10
+ HoneypotGuard is a **minimal Rails gem** that protects web forms from basic spam using:
11
+
12
+ - ๐Ÿฏ an invisible **honeypot field**
13
+ - โฑ๏ธ a simple **minimum submission delay**
14
+
15
+ It works **at the controller level** (no model validations) and immediately rejects spam requests with **`422 Unprocessable Entity`**.
16
+
17
+ Perfect for โœ‰๏ธ **contact forms**, ๐Ÿ’ฌ feedback forms, and other **non-persisted submissions**.
18
+
19
+ ---
20
+
21
+ ## ๐Ÿ“ฆ Installation
22
+
23
+ Add the gem to your Gemfile:
24
+
25
+ ```ruby
26
+ gem "honeypot_guard"
27
+ ```
28
+
29
+ Then run:
30
+
31
+ ```bash
32
+ bundle install
33
+ ```
34
+
35
+ ---
36
+
37
+ ## ๐Ÿš€ Usage
38
+
39
+ ### 1๏ธโƒฃ Add spam trap fields to your form
40
+
41
+ Inside any `form_with` or `form_for` block:
42
+
43
+ ```erb
44
+ <%= form_with url: contact_messages_path do |f| %>
45
+ <%= spam_trap_fields %>
46
+
47
+ <%= f.text_field :name %>
48
+ <%= f.email_field :email %>
49
+ <%= f.text_area :message %>
50
+ <%= f.submit "Send" %>
51
+ <% end %>
52
+ ```
53
+
54
+ This injects automatically:
55
+ - ๐Ÿ•ณ๏ธ an invisible honeypot input
56
+ - ๐Ÿงญ a hidden timestamp input
57
+
58
+ ---
59
+
60
+ ### 2๏ธโƒฃ Enable spam filtering in the controller
61
+
62
+ Include the controller concern and add the `before_action`:
63
+
64
+ ```ruby
65
+ class ContactMessagesController < ApplicationController
66
+ include HoneypotGuard::Controller
67
+
68
+ before_action :filter_spam, only: :create
69
+
70
+ def create
71
+ # normal processing
72
+ redirect_to root_path, notice: "Message sent"
73
+ end
74
+ end
75
+ ```
76
+
77
+ If spam is detected, the request is immediately stopped with:
78
+
79
+ ```http
80
+ 422 Unprocessable Entity
81
+ ```
82
+
83
+ ---
84
+
85
+ ## โš™๏ธ Configuration (Optional)
86
+
87
+ Create an initializer:
88
+
89
+ ```ruby
90
+ # config/initializers/honeypot_guard.rb
91
+ HoneypotGuard.configure do |config|
92
+ config.min_delay = 3 # seconds
93
+ # config.honeypot_field = :website
94
+ # config.timestamp_field = :rendered_at
95
+ end
96
+ ```
97
+
98
+ ---
99
+
100
+ ## ๐Ÿง  How It Works
101
+
102
+ A request is considered spam if **any** of the following is true:
103
+
104
+ 1. ๐Ÿšจ The honeypot field is filled
105
+ 2. โšก The form is submitted faster than the configured minimum delay
106
+
107
+ โœ… No JavaScript
108
+ โœ… No model validation
109
+ โœ… No database access
110
+
111
+ ---
112
+
113
+ ## โš ๏ธ Limitations
114
+
115
+ HoneypotGuard is intentionally simple:
116
+
117
+ - โŒ Not effective against advanced bots or direct HTTP submissions
118
+ - โŒ Does not replace rate limiting or firewalls
119
+ - โœ… Best used alongside tools like **Rack::Attack**
120
+
121
+ ---
122
+
123
+ ## ๐Ÿ“„ License
124
+
125
+ MIT License
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ require "rubocop/rake_task"
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ task default: %i[spec rubocop]
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "rails", "~> 7.2.0"
4
+
5
+ gemspec path: ".."
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "rails", "~> 8.0.0"
4
+
5
+ gemspec path: ".."
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "rails", "~> 8.1.0"
4
+
5
+ gemspec path: ".."
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/concern"
4
+
5
+ module HoneypotGuard
6
+ # Controller helpers used to filter out simple spam submissions.
7
+ #
8
+ # This module is intended to be included in Rails controllers
9
+ # handling form submissions, and works in combination with the
10
+ # +spam_trap_fields+ view helper.
11
+ #
12
+ module Controller
13
+ extend ActiveSupport::Concern
14
+
15
+ private
16
+
17
+ # Filters out obvious spam submissions based on:
18
+ #
19
+ # - a honeypot field that must remain empty
20
+ # - a minimum delay between form render and submission
21
+ #
22
+ # Typical usage in a controller:
23
+ #
24
+ # class ContactMessagesController < ApplicationController
25
+ # include HoneypotGuard::Controller
26
+ #
27
+ # before_action :filter_spam, only: :create
28
+ # end
29
+ #
30
+ # Combined with the ViewHelpers:
31
+ #
32
+ # <%= form_with model: @contact_message do |f| %>
33
+ # <%= spam_trap_fields %>
34
+ # ...
35
+ # <% end %>
36
+ #
37
+ # Behaviour:
38
+ # - reads the configured honeypot and timestamp fields from +params+
39
+ # - if spam is detected, logs a message and responds with <tt>422 Unprocessable Entity</tt>
40
+ # - the controller action is not executed in that case
41
+ #
42
+ def filter_spam
43
+ hp_name = HoneypotGuard.honeypot_field.to_s
44
+ ts_name = HoneypotGuard.timestamp_field.to_s
45
+
46
+ honeypot = params[hp_name]
47
+ timestamp = params[ts_name]
48
+
49
+ if spam_detected?(honeypot, timestamp)
50
+ Rails.logger.info "[HoneypotGuard] Blocked spam from #{request.remote_ip}"
51
+ head :unprocessable_entity
52
+ end
53
+ end
54
+
55
+ def spam_detected?(honeypot, timestamp)
56
+ # 1) Honeypot field must stay empty
57
+ return true if honeypot.present?
58
+
59
+ # 2) Check minimal delay
60
+ return false if timestamp.blank?
61
+
62
+ ts = Integer(timestamp) rescue nil
63
+ return false unless ts
64
+
65
+ delay = Time.now.to_i - ts
66
+ delay < HoneypotGuard.min_delay.to_i
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/railtie"
4
+
5
+ module HoneypotGuard
6
+ class Railtie < Rails::Railtie
7
+ initializer "honeypot_guard.view_helpers" do
8
+ ActiveSupport.on_load(:action_view) do
9
+ include HoneypotGuard::ViewHelpers
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HoneypotGuard
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "action_view"
4
+ require "uri"
5
+
6
+ module HoneypotGuard
7
+ # View helpers used to inject spam trap fields into Rails forms.
8
+ #
9
+ # This module provides helpers meant to be used in form views
10
+ # and works in combination with the +filter_spam+ controller
11
+ # method.
12
+ #
13
+ module ViewHelpers
14
+ # Injects invisible spam trap fields into a form.
15
+ #
16
+ # This helper adds:
17
+ # - a honeypot field that should stay empty
18
+ # - a hidden timestamp used to detect fast submissions
19
+ #
20
+ # It must be used in combination with the
21
+ # +filter_spam+ controller method.
22
+ #
23
+ # View example:
24
+ #
25
+ # <%= form_with url: contact_messages_path do |f| %>
26
+ # <%= spam_trap_fields %>
27
+ # ...
28
+ # <% end %>
29
+ #
30
+ # Controller example:
31
+ #
32
+ # class ContactMessagesController < ApplicationController
33
+ # include HoneypotGuard::Controller
34
+ # before_action :filter_spam, only: :create
35
+ # end
36
+ #
37
+ def spam_trap_fields
38
+ hp = HoneypotGuard.honeypot_field
39
+ ts = HoneypotGuard.timestamp_field
40
+
41
+ honeypot_html = content_tag(
42
+ :div,
43
+ class: "hp-field",
44
+ style: "position:absolute; left:-9999px; top:-9999px;"
45
+ ) do
46
+ label_tag(hp, "Leave this field empty") +
47
+ text_field_tag(hp, nil, autocomplete: "off")
48
+ end
49
+
50
+ timestamp_html = hidden_field_tag(ts, Time.now.to_i)
51
+
52
+ honeypot_html + timestamp_html
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "honeypot_guard/version"
4
+ require "honeypot_guard/controller"
5
+ require "honeypot_guard/view_helpers"
6
+ require "honeypot_guard/railtie" if defined?(Rails::Railtie)
7
+
8
+ # Minimal spam protection for Rails forms.
9
+ #
10
+ # Public API:
11
+ #
12
+ # Controller:
13
+ # - +filter_spam+: before_action to block obvious spam submissions
14
+ #
15
+ # Views:
16
+ # - +spam_trap_fields+: injects honeypot and timestamp fields into forms
17
+ #
18
+ module HoneypotGuard
19
+ class << self
20
+ # Name of the honeypot field in params / forms
21
+ attr_accessor :honeypot_field
22
+
23
+ # Name of the timestamp field in params / forms
24
+ attr_accessor :timestamp_field
25
+
26
+ # Minimum delay (in seconds) between form rendering and submission
27
+ attr_accessor :min_delay
28
+ end
29
+
30
+ # Defaults
31
+ self.honeypot_field = :honeypot
32
+ self.timestamp_field = :form_rendered_at
33
+ self.min_delay = 3 # seconds
34
+
35
+ # Configures HoneypotGuard.
36
+ #
37
+ # This method allows you to customize the names of the
38
+ # honeypot and timestamp fields, as well as the minimum
39
+ # submission delay.
40
+ #
41
+ # Example:
42
+ #
43
+ # # config/initializers/honeypot_guard.rb
44
+ # HoneypotGuard.configure do |config|
45
+ # config.min_delay = 3
46
+ # # config.honeypot_field = :website
47
+ # # config.timestamp_field = :rendered_at
48
+ # end
49
+ #
50
+ def self.configure
51
+ yield self
52
+ end
53
+ end
@@ -0,0 +1,4 @@
1
+ module HoneypotGuard
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata ADDED
@@ -0,0 +1,91 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: honeypot_guard
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - OpenCodeForge
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: rails
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '7.2'
19
+ - - "<"
20
+ - !ruby/object:Gem::Version
21
+ version: '9.0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ version: '7.2'
29
+ - - "<"
30
+ - !ruby/object:Gem::Version
31
+ version: '9.0'
32
+ - !ruby/object:Gem::Dependency
33
+ name: rspec
34
+ requirement: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - "~>"
37
+ - !ruby/object:Gem::Version
38
+ version: '3.12'
39
+ type: :development
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - "~>"
44
+ - !ruby/object:Gem::Version
45
+ version: '3.12'
46
+ description: Minimal Rails gem that injects honeypot fields in forms and provides
47
+ a before_action returning 422 on spam.
48
+ email:
49
+ - contact@opencodeforge.com
50
+ executables: []
51
+ extensions: []
52
+ extra_rdoc_files: []
53
+ files:
54
+ - CHANGELOG.md
55
+ - CONTRIBUTING.md
56
+ - LICENSE.txt
57
+ - README.md
58
+ - Rakefile
59
+ - gemfiles/rails_7.2.gemfile
60
+ - gemfiles/rails_8.0.gemfile
61
+ - gemfiles/rails_8.1.gemfile
62
+ - lib/honeypot_guard.rb
63
+ - lib/honeypot_guard/controller.rb
64
+ - lib/honeypot_guard/railtie.rb
65
+ - lib/honeypot_guard/version.rb
66
+ - lib/honeypot_guard/view_helpers.rb
67
+ - sig/honeypot_guard.rbs
68
+ homepage: https://github.com/OpenCodeForge/honeypot_guard
69
+ licenses:
70
+ - MIT
71
+ metadata:
72
+ source_code_uri: https://github.com/OpenCodeForge/honeypot_guard
73
+ changelog_uri: https://github.com/OpenCodeForge/honeypot_guard/blob/main/CHANGELOG.md
74
+ rdoc_options: []
75
+ require_paths:
76
+ - lib
77
+ required_ruby_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '3.0'
82
+ required_rubygems_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ requirements: []
88
+ rubygems_version: 3.7.2
89
+ specification_version: 4
90
+ summary: Simple honeypot + delay spam guard for Rails controllers
91
+ test_files: []