Class: Sendgo::WebhookService

Inherits:
Object
  • Object
show all
Defined in:
lib/sendgo/management.rb

Overview

이벤트 웹훅 구독 — 등록·심사 결과를 밀어 받는다. v2 전용.

심사는 비동기라 폴링 말고는 방법이 없었다. 구독해 두면 상태가 바뀔 때마다 도착한다.

Examples:

created = client.webhook.subscribe("https://reseller.example.com/hooks/sendgo")

# 시크릿은 이 응답에서 한 번만 나온다. 즉시 저장한다.
secret = created.dig("data", "secret")

Constant Summary collapse

RESOURCE =
"webhook"
EVENTS =

구독할 수 있는 이벤트.

%w[
  sender.status_changed
  notice_template.inspection_status_changed
  kakao_sender.status_changed
  kakao_sender.brand_message_status_changed
].freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(http:) ⇒ WebhookService

Returns a new instance of WebhookService.



470
471
472
# File 'lib/sendgo/management.rb', line 470

def initialize(http:)
  @http = http
end

Class Method Details

.verify_signature(raw_body, signature, secret) ⇒ Object

수신한 웹훅의 서명을 검증한다.

raw_body받은 바이트 그대로여야 한다. 파싱한 뒤 다시 인코딩한 값으로 계산하면 키 순서나 이스케이프 차이로 검증이 깨진다. Rails 라면 request.raw_post 다.



509
510
511
512
513
514
515
516
517
518
519
# File 'lib/sendgo/management.rb', line 509

def self.verify_signature(raw_body, signature, secret)
  expected = OpenSSL::HMAC.hexdigest("SHA256", secret, raw_body)

  ActiveSupport::SecurityUtils.secure_compare(expected, signature.to_s)
rescue NameError
  # ActiveSupport 가 없는 순수 Ruby 환경 폴백.
  # 길이가 다르면 fixed_length_secure_compare 가 던지므로 먼저 막는다.
  return false unless expected.bytesize == signature.to_s.bytesize

  OpenSSL.fixed_length_secure_compare(expected, signature.to_s)
end

Instance Method Details

#showObject

현재 구독 설정. 마지막 전송 결과(+lastStatus+)도 함께 온다.



475
476
477
# File 'lib/sendgo/management.rb', line 475

def show
  @http.get(RESOURCE)
end

#subscribe(url, secret: nil, events: nil, enabled: true) ⇒ Object

구독 생성·수정.

secret 을 생략하면 서버가 만들어 이 응답에서 한 번만 돌려준다. 이미 시크릿이 있는 상태에서 생략하면 기존 값을 유지한다 — URL 만 바꾸는 호출이 서명 키를 날리지 않는다.

events 가 nil 이면 전체 구독이다.



486
487
488
489
490
491
492
# File 'lib/sendgo/management.rb', line 486

def subscribe(url, secret: nil, events: nil, enabled: true)
  body = { url: url, enabled: enabled }
  body[:secret] = secret unless secret.nil?
  body[:events] = events unless events.nil?

  @http.put(RESOURCE, body)
end

#testObject

테스트 이벤트 발송. 구독 목록과 무관하게 도착한다.



495
496
497
# File 'lib/sendgo/management.rb', line 495

def test
  @http.post("#{RESOURCE}/test", {})
end

#unsubscribeObject

구독 해지.



500
501
502
# File 'lib/sendgo/management.rb', line 500

def unsubscribe
  @http.delete(RESOURCE)
end