fix(hmac): verify contact inbox hmac server-side
This commit is contained in:
@@ -1,5 +1,30 @@
|
||||
module HmacConcern
|
||||
def hmac_verified?
|
||||
ActiveModel::Type::Boolean.new.cast(params[:hmac_verified]).present?
|
||||
return false unless hmac_verification_params_valid?
|
||||
|
||||
expected_hash = OpenSSL::HMAC.hexdigest(
|
||||
'sha256',
|
||||
hmac_channel.hmac_token,
|
||||
@contact.identifier
|
||||
)
|
||||
identifier_hash = params[:identifier_hash].to_s
|
||||
return false unless identifier_hash.bytesize == expected_hash.bytesize
|
||||
|
||||
ActiveSupport::SecurityUtils.secure_compare(identifier_hash, expected_hash)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def hmac_verification_params_valid?
|
||||
params[:identifier_hash].present? &&
|
||||
@contact&.identifier.present? &&
|
||||
params[:identifier].to_s == @contact.identifier &&
|
||||
hmac_channel.present?
|
||||
end
|
||||
|
||||
def hmac_channel
|
||||
return if @inbox.blank?
|
||||
|
||||
@hmac_channel ||= @inbox.channel if @inbox.channel.respond_to?(:hmac_token)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,7 +2,7 @@ require 'rails_helper'
|
||||
|
||||
RSpec.describe '/api/v1/accounts/{account.id}/contacts/:id/contact_inboxes', type: :request do
|
||||
let(:account) { create(:account) }
|
||||
let(:contact) { create(:contact, account: account, email: 'f.o.o.b.a.r@gmail.com') }
|
||||
let(:contact) { create(:contact, account: account, email: 'f.o.o.b.a.r@gmail.com', identifier: 'contact-identifier') }
|
||||
let(:channel_twilio_sms) { create(:channel_twilio_sms, account: account) }
|
||||
let(:channel_email) { create(:channel_email, account: account) }
|
||||
let(:channel_api) { create(:channel_api, account: account) }
|
||||
@@ -45,7 +45,7 @@ RSpec.describe '/api/v1/accounts/{account.id}/contacts/:id/contact_inboxes', typ
|
||||
expect(contact.reload.contact_inboxes.map(&:inbox_id)).to include(channel_email.inbox.id)
|
||||
end
|
||||
|
||||
it 'creates an hmac verified contact inbox' do
|
||||
it 'does not trust client supplied hmac_verified param' do
|
||||
create(:inbox_member, inbox: channel_api.inbox, user: agent)
|
||||
expect do
|
||||
post "/api/v1/accounts/#{account.id}/contacts/#{contact.id}/contact_inboxes",
|
||||
@@ -54,6 +54,23 @@ RSpec.describe '/api/v1/accounts/{account.id}/contacts/:id/contact_inboxes', typ
|
||||
as: :json
|
||||
end.to change(ContactInbox, :count).by(1)
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
contact_inbox = contact.reload.contact_inboxes.find_by(inbox_id: channel_api.inbox.id)
|
||||
expect(contact_inbox).to be_present
|
||||
expect(contact_inbox.hmac_verified).to be(false)
|
||||
end
|
||||
|
||||
it 'creates an hmac verified contact inbox with a valid identifier hash' do
|
||||
create(:inbox_member, inbox: channel_api.inbox, user: agent)
|
||||
identifier_hash = OpenSSL::HMAC.hexdigest('sha256', channel_api.hmac_token, contact.identifier)
|
||||
|
||||
expect do
|
||||
post "/api/v1/accounts/#{account.id}/contacts/#{contact.id}/contact_inboxes",
|
||||
params: { inbox_id: channel_api.inbox.id, identifier: contact.identifier, identifier_hash: identifier_hash },
|
||||
headers: agent.create_new_auth_token,
|
||||
as: :json
|
||||
end.to change(ContactInbox, :count).by(1)
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
contact_inbox = contact.reload.contact_inboxes.find_by(inbox_id: channel_api.inbox.id)
|
||||
expect(contact_inbox).to be_present
|
||||
|
||||
Reference in New Issue
Block a user