diff --git a/lib/line/bot/v2/webhook_parser.rb b/lib/line/bot/v2/webhook_parser.rb index 18afdfd5..b9d07003 100644 --- a/lib/line/bot/v2/webhook_parser.rb +++ b/lib/line/bot/v2/webhook_parser.rb @@ -15,6 +15,44 @@ def initialize(channel_secret:) @channel_secret = channel_secret end + # Parse events from the raw request body and validate the signature. + # + # @param body [String] + # The unmodified request body (exactly as received). + # @param signature [String] + # The value of the 'X-LINE-Signature' header. + # @return [Array] + # An array of event objects. Recognized events become instances of classes + # under `Line::Bot::V2::Webhook::*Event`; otherwise, they're returned as `Struct`. + # `Struct` is returned as fallback only when the event class is not defined in line-bot-sdk library. + # When you update the SDK, you may not need to handle `Struct` anymore. + # @raise [InvalidSignatureError] + # If the signature fails verification. + # + # @example Sinatra usage + # def parser + # @parser ||= Line::Bot::V2::WebhookParser.new(channel_secret: ENV.fetch("LINE_CHANNEL_SECRET")) + # end + # + # post '/callback' do + # body = request.body.read + # signature = request.env['HTTP_X_LINE_SIGNATURE'] + # + # begin + # events = parser.parse(body, signature) + # rescue Line::Bot::V2::WebhookParser::InvalidSignatureError + # halt 400, { 'Content-Type' => 'text/plain' }, 'Bad Request' + # end + # + # # Handle events... + # events.each do |event| + # case event + # when Line::Bot::V2::Webhook::MessageEvent + # handle_message_event(event) + # ... + # end + # "OK" + # end def parse(body, signature) raise InvalidSignatureError.new("Invalid signature: #{signature}") unless verify_signature(body: body, signature: signature) diff --git a/sig/line/bot/v2/webhook_parser.rbs b/sig/line/bot/v2/webhook_parser.rbs index 658d3f5c..1c181388 100644 --- a/sig/line/bot/v2/webhook_parser.rbs +++ b/sig/line/bot/v2/webhook_parser.rbs @@ -2,9 +2,16 @@ module Line module Bot module V2 class WebhookParser + class InvalidSignatureError < ::StandardError + end + def initialize: (channel_secret: String) -> void - def parse: (String body, String signature) -> Hash[Symbol, untyped] + def parse: ( + body: String, + signature: String + ) -> Array[Webhook::Event | ::Struct[untyped]] + private @@ -21,6 +28,8 @@ module Line def pascalize: (String|Symbol str) -> String def singularize: (String|Symbol str) -> String + + def deep_hash_to_struct: (untyped) -> untyped end end end