Class: Line::Bot::V2::WebhookParser
- Inherits:
-
Object
- Object
- Line::Bot::V2::WebhookParser
- Defined in:
- lib/line/bot/v2/webhook_parser.rb,
sig/line/bot/v2/webhook_parser.rbs
Defined Under Namespace
Classes: InvalidSignatureError
Instance Method Summary collapse
-
#initialize(channel_secret:, skip_signature_verification: nil) ⇒ WebhookParser
constructor
Initialize webhook parser.
-
#parse(body:, signature:) ⇒ Array<Line::Bot::V2::Webhook::Event>
Parse events from the raw request body and validate the signature.
- #secure_compare(a, b) ⇒ Boolean
-
#variable_secure_compare(a, b) ⇒ Boolean
To avoid timing attacks.
- #verify_signature(body:, signature:) ⇒ Boolean
Constructor Details
#initialize(channel_secret:, skip_signature_verification: nil) ⇒ WebhookParser
Initialize webhook parser
25 26 27 28 |
# File 'lib/line/bot/v2/webhook_parser.rb', line 25 def initialize(channel_secret:, skip_signature_verification: nil) @channel_secret = channel_secret @skip_signature_verification = skip_signature_verification end |
Instance Method Details
#parse(body:, signature:) ⇒ Array<Line::Bot::V2::Webhook::Event>
Parse events from the raw request body and validate the signature.
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/line/bot/v2/webhook_parser.rb', line 71 def parse(body:, signature:) should_skip = @skip_signature_verification&.call || false unless should_skip == true || verify_signature(body: body, signature: signature) raise InvalidSignatureError.new("Invalid signature: #{signature}") end data = JSON.parse(body.chomp, symbolize_names: true) data = Line::Bot::V2::Utils.deep_underscore(data) data = Line::Bot::V2::Utils.deep_convert_reserved_words(data) data = Line::Bot::V2::Utils.deep_symbolize(data) data[:events].map do |event| Line::Bot::V2::Webhook::Event.create(**event) # steep:ignore end end |
#secure_compare(a, b) ⇒ Boolean
101 102 103 104 105 106 107 108 109 |
# File 'lib/line/bot/v2/webhook_parser.rb', line 101 def secure_compare(a, b) return false unless a.bytesize == b.bytesize l = a.unpack("C#{a.bytesize}") res = 0 b.each_byte { |byte| res |= byte ^ l.shift } # steep:ignore ArgumentTypeMismatch res == 0 end |
#variable_secure_compare(a, b) ⇒ Boolean
To avoid timing attacks
97 98 99 |
# File 'lib/line/bot/v2/webhook_parser.rb', line 97 def variable_secure_compare(a, b) secure_compare(::Digest::SHA256.hexdigest(a), ::Digest::SHA256.hexdigest(b)) end |
#verify_signature(body:, signature:) ⇒ Boolean
88 89 90 91 92 |
# File 'lib/line/bot/v2/webhook_parser.rb', line 88 def verify_signature(body:, signature:) hash = OpenSSL::HMAC.digest(OpenSSL::Digest.new('SHA256'), @channel_secret, body) expected = Base64.strict_encode64(hash) variable_secure_compare(signature, expected) end |