@@ -209,6 +209,11 @@ def self.valid_timestamp?(headers, config)
209
209
end
210
210
211
211
# Parse timestamp value supporting both ISO 8601 UTC and Unix formats
212
+ #
213
+ # @param timestamp_value [String] The timestamp string to parse
214
+ # @return [Integer, nil] Epoch seconds if parsing succeeds, nil otherwise
215
+ # @note Security: Strict validation prevents various injection attacks
216
+ # @api private
212
217
def self . parse_timestamp ( timestamp_value )
213
218
# Reject if contains any control characters, whitespace, or null bytes
214
219
if timestamp_value =~ /[\u0000 -\u001F \u007F -\u009F ]/
@@ -230,11 +235,20 @@ def self.parse_timestamp(timestamp_value)
230
235
end
231
236
232
237
# Check if timestamp string looks like ISO 8601 UTC format (must have UTC indicator)
238
+ #
239
+ # @param timestamp_value [String] The timestamp string to check
240
+ # @return [Boolean] true if it appears to be ISO 8601 format (with or without UTC indicator)
241
+ # @api private
233
242
def self . iso8601_timestamp? ( timestamp_value )
234
243
!!( timestamp_value =~ /\A \d {4}-\d {2}-\d {2}[T ]\d {2}:\d {2}:\d {2}(?:\. \d +)?(Z|\+ 00:00|\+ 0000)?\z / )
235
244
end
236
245
237
246
# Parse ISO 8601 UTC timestamp string (must have UTC indicator)
247
+ #
248
+ # @param timestamp_value [String] ISO 8601 timestamp string
249
+ # @return [Integer, nil] Epoch seconds if parsing succeeds, nil otherwise
250
+ # @note Only accepts UTC timestamps (ending with 'Z', '+00:00', '+0000')
251
+ # @api private
238
252
def self . parse_iso8601_timestamp ( timestamp_value )
239
253
if timestamp_value =~ /\A (\d {4}-\d {2}-\d {2}) (\d {2}:\d {2}:\d {2}(?:\. \d +)?)(?: )\+ 0000\z /
240
254
timestamp_value = "#{ $1} T#{ $2} +00:00"
@@ -246,6 +260,11 @@ def self.parse_iso8601_timestamp(timestamp_value)
246
260
end
247
261
248
262
# Parse Unix timestamp string (must be positive integer, no leading zeros except for "0")
263
+ #
264
+ # @param timestamp_value [String] Unix timestamp string
265
+ # @return [Integer, nil] Epoch seconds if parsing succeeds, nil otherwise
266
+ # @note Only accepts positive integer values, no leading zeros except for "0"
267
+ # @api private
249
268
def self . parse_unix_timestamp ( timestamp_value )
250
269
return nil unless unix_timestamp? ( timestamp_value )
251
270
ts = timestamp_value . to_i
@@ -254,6 +273,10 @@ def self.parse_unix_timestamp(timestamp_value)
254
273
end
255
274
256
275
# Check if timestamp string looks like Unix timestamp format (no leading zeros except "0")
276
+ #
277
+ # @param timestamp_value [String] The timestamp string to check
278
+ # @return [Boolean] true if it appears to be Unix timestamp format
279
+ # @api private
257
280
def self . unix_timestamp? ( timestamp_value )
258
281
return true if timestamp_value == "0"
259
282
!!( timestamp_value =~ /\A [1-9]\d *\z / )
@@ -306,7 +329,7 @@ def self.compute_signature(payload:, headers:, secret:, config:)
306
329
# - {body}: Replaced with the raw payload
307
330
# @example Template usage
308
331
# template: "{version}:{timestamp}:{body}"
309
- # result: "v0:1609459200:{"event": "push"}"
332
+ # result: "v0:1609459200:{\ "event\":\ "push\ "}"
310
333
# @api private
311
334
def self . build_signing_payload ( payload :, headers :, config :)
312
335
template = config [ :payload_template ]
@@ -336,7 +359,7 @@ def self.build_signing_payload(payload:, headers:, config:)
336
359
# - :algorithm_prefixed: "sha256=abc123..." (GitHub style)
337
360
# - :hash_only: "abc123..." (Shopify style)
338
361
# - :version_prefixed: "v0=abc123..." (Slack style)
339
- # @note Defaults to algorithm_prefixed format for unknown format styles
362
+ # @note Defaults to algorithm-prefixed format for unknown format styles
340
363
# @api private
341
364
def self . format_signature ( hash , config )
342
365
format_style = FORMATS [ config [ :format ] ]
0 commit comments