hooks-ruby 0.2.1 → 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: 47555e043e83129f208e5925c22dbbf12aadba0358a70272461952355251c869
4
- data.tar.gz: b2760979c328b79cf82fe8b5a37a67261f2b5085208488ca928662e1915d9f06
3
+ metadata.gz: efc93a22af173a3085d2af45a0787501cf4e520e0aa917c7b4b8ee477a477820
4
+ data.tar.gz: 06c6177f4356d06e59ceaf2f7e9c62848752ee1a5d298981c2820c1732906424
5
5
  SHA512:
6
- metadata.gz: 90b666eb68b986092e56e6db8140af3e6aae5b03a59e0e546beeee4a314a97ed75aaf4122687087cc58b258d88462a6fc5829339f56510e9d123f9b0d7c414ed
7
- data.tar.gz: e50173bf684c3b458fe489667b05a65737658160c5a01603f7b8061419945fe41b07d04e61861524c8af5b445e2d63aa78b90ac1a3a07bb2fed481c50cc04406
6
+ metadata.gz: e4bed95c7e1f41cd7188847773b83e1d7e1a463122545cc5c0330348539f81b2ed254c9e7ff161b2922b8f064ec46174288b3557be4c2d63604405ab931adb0d
7
+ data.tar.gz: fe7cdde0b508f5bcf1e354f6c3b2583530ad27f27d63686712d05830581b849fc2d8e61cad5ba1dd8d4283e182b823625d4e164bd9fa4909ae6be7be3d0ce360
data/README.md CHANGED
@@ -50,9 +50,11 @@ Here is a very high-level overview of how Hooks works:
50
50
  ```yaml
51
51
  # file: config/endpoints/hello.yml
52
52
  path: /hello
53
- handler: MyCustomHandler # This is a custom handler plugin you would define in the plugins/handlers directory
53
+ handler: my_custom_handler # This is a custom handler plugin you would define in the plugins/handlers directory (snake_case)
54
54
  ```
55
55
 
56
+ > Note: If your handler's class name is `MyCustomHandler`, you would define it in the `plugins/handlers/my_custom_handler.rb` file. The `handler` field in the endpoint configuration file should be the snake_case version of the class name. So if your handler class is `MyCustomHandler`, you would use `my_custom_handler` in the endpoint configuration file.
57
+
56
58
  3. Now create a corresponding handler plugin in the `plugins/handlers` directory. Here is an example of a simple handler plugin:
57
59
 
58
60
  ```ruby
@@ -64,7 +66,7 @@ Here is a very high-level overview of how Hooks works:
64
66
  # For this example, we will just return a success message
65
67
  {
66
68
  status: "success",
67
- handler: "MyCustomHandler",
69
+ handler: "my_custom_handler",
68
70
  payload_received: payload,
69
71
  timestamp: Time.now.utc.iso8601
70
72
  }
@@ -208,16 +210,16 @@ Endpoint configurations are defined in the `config/endpoints` directory. Each en
208
210
  ```yaml
209
211
  # file: config/endpoints/hello.yml
210
212
  path: /hello # becomes /webhooks/hello based on the root_path in hooks.yml
211
- handler: HelloHandler # This is a custom handler plugin you would define in the plugins/handlers
213
+ handler: hello_handler # This is a custom handler plugin you would define in the plugins/handlers
212
214
  ```
213
215
 
214
216
  ```yaml
215
217
  # file: config/endpoints/goodbye.yml
216
218
  path: /goodbye # becomes /webhooks/goodbye based on the root_path in hooks.yml
217
- handler: GoodbyeHandler # This is another custom handler plugin you would define in the plugins/handlers
219
+ handler: goodbye_handler # This is another custom handler plugin you would define in the plugins/handlers
218
220
 
219
221
  auth:
220
- type: Goodbye # This is a custom authentication plugin you would define in the plugins/auth
222
+ type: goodbye # This is a custom authentication plugin you would define in the plugins/auth
221
223
  secret_env_key: GOODBYE_API_KEY # the name of the environment variable containing the secret
222
224
  header: Authorization
223
225
 
@@ -255,7 +257,7 @@ class GoodbyeHandler < Hooks::Plugins::Handlers::Base
255
257
  # Ditto for the goodbye endpoint
256
258
  {
257
259
  message: "goodbye webhook processed successfully",
258
- handler: "GoodbyeHandler",
260
+ handler: "goodbye_handler",
259
261
  timestamp: Time.now.utc.iso8601
260
262
  }
261
263
  end
data/lib/hooks/app/api.rb CHANGED
@@ -4,6 +4,7 @@ require "grape"
4
4
  require "json"
5
5
  require "securerandom"
6
6
  require_relative "helpers"
7
+ #require_relative "network/ip_filtering"
7
8
  require_relative "auth/auth"
8
9
  require_relative "rack_env_builder"
9
10
  require_relative "../plugins/handlers/base"
@@ -82,6 +83,13 @@ module Hooks
82
83
  plugin.on_request(rack_env)
83
84
  end
84
85
 
86
+ # TODO: IP filtering before processing the request if defined
87
+ # If IP filtering is enabled at either global or endpoint level, run the filtering rules
88
+ # before processing the request
89
+ #if config[:ip_filtering] || endpoint_config[:ip_filtering]
90
+ #ip_filtering!(headers, endpoint_config, config, request_context, rack_env)
91
+ #end
92
+
85
93
  enforce_request_limits(config, request_context)
86
94
  request.body.rewind
87
95
  raw_body = request.body.read
@@ -74,7 +74,7 @@ module Hooks
74
74
 
75
75
  # Load handler class
76
76
  #
77
- # @param handler_class_name [String] The name of the handler class to load
77
+ # @param handler_class_name [String] The name of the handler in snake_case (e.g., "github_handler")
78
78
  # @return [Object] An instance of the loaded handler class
79
79
  # @raise [StandardError] If handler cannot be found
80
80
  def load_handler(handler_class_name)
@@ -72,6 +72,8 @@ module Hooks
72
72
  end
73
73
 
74
74
  # Add HTTP headers to the environment with proper Rack naming convention
75
+ # Note: This will generally add headers like HTTP_X_CUSTOM_HEADER. For example, the HTTP_X_FORWARDED_FOR
76
+ # is a common header that is used to pass the original client IP address through proxies.
75
77
  #
76
78
  # @param rack_env [Hash] Environment hash to modify
77
79
  def add_http_headers(rack_env)
@@ -125,11 +125,12 @@ module Hooks
125
125
  # Must not be empty or only whitespace
126
126
  return false if handler_name.strip.empty?
127
127
 
128
- # Must match a safe pattern: alphanumeric + underscore, starting with uppercase
129
- return false unless handler_name.match?(/\A[A-Z][a-zA-Z0-9_]*\z/)
128
+ # Must match strict snake_case pattern: starts with lowercase, no trailing/consecutive underscores
129
+ return false unless handler_name.match?(/\A[a-z][a-z0-9]*(?:_[a-z0-9]+)*\z/)
130
130
 
131
- # Must not be a system/built-in class name
132
- return false if Hooks::Security::DANGEROUS_CLASSES.include?(handler_name)
131
+ # Convert to PascalCase for security check (since DANGEROUS_CLASSES uses PascalCase)
132
+ pascal_case_name = handler_name.split("_").map(&:capitalize).join("")
133
+ return false if Hooks::Security::DANGEROUS_CLASSES.include?(pascal_case_name)
133
134
 
134
135
  true
135
136
  end
@@ -61,11 +61,13 @@ module Hooks
61
61
 
62
62
  # Get handler plugin class by name
63
63
  #
64
- # @param handler_name [String] Name of the handler (e.g., "DefaultHandler", "Team1Handler")
64
+ # @param handler_name [String] Name of the handler in snake_case (e.g., "github_handler", "team_1_handler")
65
65
  # @return [Class] The handler plugin class
66
66
  # @raise [StandardError] if handler not found
67
67
  def get_handler_plugin(handler_name)
68
- plugin_class = @handler_plugins[handler_name]
68
+ # Convert snake_case to PascalCase for registry lookup
69
+ pascal_case_name = handler_name.split("_").map(&:capitalize).join("")
70
+ plugin_class = @handler_plugins[pascal_case_name]
69
71
 
70
72
  unless plugin_class
71
73
  raise StandardError, "Handler plugin '#{handler_name}' not found. Available handlers: #{@handler_plugins.keys.join(', ')}"
@@ -4,6 +4,7 @@ require "rack/utils"
4
4
  require_relative "../../core/log"
5
5
  require_relative "../../core/global_components"
6
6
  require_relative "../../core/component_access"
7
+ require_relative "timestamp_validator"
7
8
 
8
9
  module Hooks
9
10
  module Plugins
@@ -53,6 +54,13 @@ module Hooks
53
54
  return secret.strip
54
55
  end
55
56
 
57
+ # Get timestamp validator instance
58
+ #
59
+ # @return [TimestampValidator] Singleton timestamp validator instance
60
+ def self.timestamp_validator
61
+ TimestampValidator.new
62
+ end
63
+
56
64
  # Find a header value by name with case-insensitive matching
57
65
  #
58
66
  # @param headers [Hash] HTTP headers from the request
@@ -3,7 +3,6 @@
3
3
  require "openssl"
4
4
  require "time"
5
5
  require_relative "base"
6
- require_relative "timestamp_validator"
7
6
 
8
7
  module Hooks
9
8
  module Plugins
@@ -271,14 +270,6 @@ module Hooks
271
270
  timestamp_validator.valid?(timestamp_value, tolerance)
272
271
  end
273
272
 
274
- # Get timestamp validator instance
275
- #
276
- # @return [TimestampValidator] Singleton timestamp validator instance
277
- # @api private
278
- def self.timestamp_validator
279
- @timestamp_validator ||= TimestampValidator.new
280
- end
281
-
282
273
  # Compute HMAC signature based on configuration requirements
283
274
  #
284
275
  # Generates the expected HMAC signature for the given payload using the
data/lib/hooks/version.rb CHANGED
@@ -4,5 +4,5 @@
4
4
  module Hooks
5
5
  # Current version of the Hooks webhook framework
6
6
  # @return [String] The version string following semantic versioning
7
- VERSION = "0.2.1".freeze
7
+ VERSION = "0.3.0".freeze
8
8
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hooks-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - github