form_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: 4c52f84444c765efffe63b1be6771ba9a8bfcbbe077d2809f38935b66a03fa32
4
+ data.tar.gz: 9081dfd61917416bc8cb83b79919e3c93930bee9e637513458a2f777d0202283
5
+ SHA512:
6
+ metadata.gz: f6a81703c40d8e923fe7bd52163f8d3ca8e4267543c0386904bfbf21908bdf3789a64c75a5dacb89e8ab620f6744ee370ecad456f26672fa20d512f7cae64aff
7
+ data.tar.gz: 4438c1d1000c698a989c84911ec4c803dd74e67a4f63621dc43a8fd8fde4eace8ef56e52231c36f64e8690d53631980a0ff99ca4fec827f4be4261f82f45d8bc
data/CHANGELOG.md ADDED
@@ -0,0 +1 @@
1
+ ## [Unreleased]
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025 Stoyan Nikolov
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,38 @@
1
+ # Form Guard
2
+
3
+ Form Guard is a lightweight gem to protect your forms from bots and spammy submissions using a simple and effective honeypot + timing strategy.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```bash
10
+ gem 'form_guard'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ ```bash
16
+ bundle install
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ 1. Add hidden guard field to your forms:
22
+ ```bash
23
+ <%= form_guard_fields %>
24
+ ```
25
+
26
+ ## How it works
27
+
28
+ - Bots tend to fill all fields — including hidden ones. If the honeypot is filled, the submission is rejected.
29
+
30
+ - Bots submit instantly. If the form is submitted too quickly (under 2 seconds), it’s probably a bot.
31
+
32
+ ## Contributing
33
+
34
+ Bug reports and pull requests are welcome on GitHub at https://github.com/amigobg/form_guard.
35
+
36
+ ## License
37
+
38
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rake"
4
+ require "rake/testtask"
5
+
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.libs << "test"
8
+ t.pattern = "test/**/*_test.rb"
9
+ t.verbose = true
10
+ end
11
+
12
+ task default: :test
@@ -0,0 +1,28 @@
1
+ require "active_support/concern"
2
+
3
+ module FormGuard
4
+ module Controller
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ before_action :verify_honeypot!
9
+ end
10
+
11
+ private
12
+ def verify_honeypot!
13
+ return unless request.post? || request.patch? || request.put?
14
+
15
+ config = FormGuard.configuration
16
+ min_delay = config.min_delay
17
+
18
+ raw_params = params.to_unsafe_h
19
+
20
+ honeypot_value = raw_params.find { |key, _| key.start_with?(config.honeypot_field_prefix) }&.last
21
+ honeypot_time = raw_params.find { |key, _| key.start_with?(config.honeypot_time_prefix) }&.last.to_i
22
+
23
+ if honeypot_value.present? || honeypot_time <= 0 || (Time.now.to_i - honeypot_time) < min_delay
24
+ redirect_to root_path, alert: "Suspicious activity detected"
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,17 @@
1
+ require "rails/railtie"
2
+
3
+ module FormGuard
4
+ class Railtie < Rails::Railtie
5
+ initializer "form_guard.action_view_integration" do
6
+ ActiveSupport.on_load(:action_view, run_once: true) do
7
+ include FormGuard::ViewHelper if defined?(ActionView)
8
+ end
9
+ end
10
+
11
+ initializer "form_guard.action_controller_integration" do
12
+ ActiveSupport.on_load(:action_controller, run_once: true) do
13
+ include FormGuard::Controller if defined?(ActionController)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,3 @@
1
+ module FormGuard
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,16 @@
1
+ require "securerandom"
2
+
3
+ module FormGuard
4
+ module ViewHelper
5
+ def form_guard_fields
6
+ config = FormGuard.configuration
7
+
8
+ tag.div style: "display:none;", "aria-hidden": "true" do
9
+ safe_join([
10
+ hidden_field_tag("#{config.honeypot_field_prefix}#{SecureRandom.hex(4)}", nil, autocomplete: "off"),
11
+ hidden_field_tag( "#{config.honeypot_time_prefix}#{SecureRandom.hex(4)}", Time.now.to_i, autocomplete: "off")
12
+ ])
13
+ end
14
+ end
15
+ end
16
+ end
data/lib/form_guard.rb ADDED
@@ -0,0 +1,29 @@
1
+ require_relative "form_guard/version"
2
+ require_relative "form_guard/view_helper"
3
+ require_relative "form_guard/controller"
4
+ require_relative "form_guard/railtie"
5
+
6
+ module FormGuard
7
+ class Error < StandardError; end
8
+
9
+ class << self
10
+ attr_accessor :configuration
11
+ end
12
+
13
+ def self.configure
14
+ self.configuration ||= Configuration.new
15
+ yield(configuration)
16
+ end
17
+
18
+ class Configuration
19
+ attr_accessor :min_delay, :honeypot_field_prefix, :honeypot_time_prefix
20
+
21
+ def initialize
22
+ @min_delay = 2
23
+ @honeypot_field_prefix = "field_"
24
+ @honeypot_time_prefix = "ts_"
25
+ end
26
+ end
27
+
28
+ FormGuard.configuration ||= FormGuard::Configuration.new
29
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+
5
+ class TestFormGuard < Minitest::Test
6
+ def test_that_it_has_a_version_number
7
+ refute_nil ::FormGuard::VERSION
8
+ end
9
+
10
+ def test_it_has_default_configuration
11
+ config = FormGuard.configuration
12
+ assert_equal 2, config.min_delay
13
+ assert_equal "field_", config.honeypot_field_prefix
14
+ assert_equal "ts_", config.honeypot_time_prefix
15
+ end
16
+
17
+ def test_configure_changes_settings
18
+ FormGuard.configure do |config|
19
+ config.min_delay = 5
20
+ config.honeypot_field_prefix = "hp_"
21
+ config.honeypot_time_prefix = "time_"
22
+ end
23
+
24
+ config = FormGuard.configuration
25
+ assert_equal 5, config.min_delay
26
+ assert_equal "hp_", config.honeypot_field_prefix
27
+ assert_equal "time_", config.honeypot_time_prefix
28
+ end
29
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/setup"
4
+ require "minitest/autorun"
5
+ require "mocha/minitest"
6
+ require "rails"
7
+ require "action_controller"
8
+ require "action_view"
9
+ require "form_guard"
10
+
11
+ class TestController < ActionController::Base
12
+ include FormGuard::Controller
13
+ end
14
+
15
+ class TestViewContext
16
+ include ActionView::Helpers::FormTagHelper
17
+ include ActionView::Helpers::TagHelper
18
+ include ActionView::Context
19
+ include FormGuard::ViewHelper
20
+
21
+ def root_path
22
+ "/"
23
+ end
24
+ end
metadata ADDED
@@ -0,0 +1,141 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: form_guard
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Stoyan Nikolov
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2025-06-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '6.0'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '8.0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '6.0'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '8.0'
33
+ - !ruby/object:Gem::Dependency
34
+ name: activesupport
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '6.0'
40
+ - - "<"
41
+ - !ruby/object:Gem::Version
42
+ version: '8.0'
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: '6.0'
50
+ - - "<"
51
+ - !ruby/object:Gem::Version
52
+ version: '8.0'
53
+ - !ruby/object:Gem::Dependency
54
+ name: minitest
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - "~>"
58
+ - !ruby/object:Gem::Version
59
+ version: '5.16'
60
+ type: :development
61
+ prerelease: false
62
+ version_requirements: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - "~>"
65
+ - !ruby/object:Gem::Version
66
+ version: '5.16'
67
+ - !ruby/object:Gem::Dependency
68
+ name: actionpack
69
+ requirement: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - "~>"
72
+ - !ruby/object:Gem::Version
73
+ version: '6.0'
74
+ type: :development
75
+ prerelease: false
76
+ version_requirements: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - "~>"
79
+ - !ruby/object:Gem::Version
80
+ version: '6.0'
81
+ - !ruby/object:Gem::Dependency
82
+ name: actionview
83
+ requirement: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - "~>"
86
+ - !ruby/object:Gem::Version
87
+ version: '6.0'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - "~>"
93
+ - !ruby/object:Gem::Version
94
+ version: '6.0'
95
+ description: FormGuard provides a simple way to prevent bot form submissions in Rails
96
+ applications using honeypot fields and timestamp-based validation.
97
+ email:
98
+ - s.nikolov@roomspilot.com
99
+ executables: []
100
+ extensions: []
101
+ extra_rdoc_files: []
102
+ files:
103
+ - CHANGELOG.md
104
+ - LICENSE.txt
105
+ - README.md
106
+ - Rakefile
107
+ - lib/form_guard.rb
108
+ - lib/form_guard/controller.rb
109
+ - lib/form_guard/railtie.rb
110
+ - lib/form_guard/version.rb
111
+ - lib/form_guard/view_helper.rb
112
+ - test/test_form_guard.rb
113
+ - test/test_helper.rb
114
+ homepage: https://github.com/amigobg/form_guard
115
+ licenses:
116
+ - MIT
117
+ metadata:
118
+ source_code_uri: https://github.com/amigobg/form_guard
119
+ changelog_uri: https://github.com/amigobg/form_guard/blob/master/CHANGELOG.md
120
+ bug_tracker_uri: https://github.com/amigobg/form_guard/issues
121
+ post_install_message:
122
+ rdoc_options: []
123
+ require_paths:
124
+ - lib
125
+ required_ruby_version: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ version: 3.0.0
130
+ required_rubygems_version: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ requirements: []
136
+ rubygems_version: 3.5.22
137
+ signing_key:
138
+ specification_version: 4
139
+ summary: A Rails gem to protect forms from bot submissions using honeypot and timestamp
140
+ checks.
141
+ test_files: []