Class: Line::Bot::V2::WebhookParser

Inherits:
Object
  • Object
show all
Defined in:
lib/line/bot/v2/webhook_parser.rb

Defined Under Namespace

Classes: InvalidSignatureError

Instance Method Summary collapse

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.

Examples:

Sinatra usage

def parser
  @parser ||= Line::Bot::V2::WebhookParser.new(
    channel_secret: ENV.fetch("LINE_CHANNEL_SECRET"),
    skip_signature_verification: -> { ENV['SKIP_SIGNATURE_VERIFICATION'] == 'true' }
  )
end

post '/callback' do
  body = request.body.read
  signature = request.env['HTTP_X_LINE_SIGNATURE']

  begin
    events = parser.parse(body: body, signature: 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

Raises:



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

#verify_signature(body:, signature:) ⇒ Object



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