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 +4 -4
- data/README.md +8 -6
- data/lib/hooks/app/api.rb +8 -0
- data/lib/hooks/app/helpers.rb +1 -1
- data/lib/hooks/app/rack_env_builder.rb +2 -0
- data/lib/hooks/core/config_validator.rb +5 -4
- data/lib/hooks/core/plugin_loader.rb +4 -2
- data/lib/hooks/plugins/auth/base.rb +8 -0
- data/lib/hooks/plugins/auth/hmac.rb +0 -9
- data/lib/hooks/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: efc93a22af173a3085d2af45a0787501cf4e520e0aa917c7b4b8ee477a477820
|
4
|
+
data.tar.gz: 06c6177f4356d06e59ceaf2f7e9c62848752ee1a5d298981c2820c1732906424
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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:
|
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: "
|
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:
|
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:
|
219
|
+
handler: goodbye_handler # This is another custom handler plugin you would define in the plugins/handlers
|
218
220
|
|
219
221
|
auth:
|
220
|
-
type:
|
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: "
|
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
|
data/lib/hooks/app/helpers.rb
CHANGED
@@ -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
|
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
|
129
|
-
return false unless handler_name.match?(/\A[
|
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
|
-
#
|
132
|
-
|
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., "
|
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
|
-
|
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