Signal fixes
This commit is contained in:
parent
0e8c9be247
commit
457a86ebcd
7 changed files with 91 additions and 70 deletions
|
|
@ -8,8 +8,8 @@ class CdrSignalChannelsController < ApplicationController
|
|||
{
|
||||
id: channel.id,
|
||||
phone_number: channel.options['phone_number'],
|
||||
bot_token: channel.options['bot_token'],
|
||||
bot_endpoint: channel.options['bot_endpoint']
|
||||
# bot_token intentionally excluded - bridge-worker should look it up from cdr database
|
||||
}
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -115,7 +115,11 @@ class ChannelsCdrSignalController < ApplicationController
|
|||
|
||||
channel = channel_for_token(token)
|
||||
return render json: {}, status: 401 if !channel || !channel.active
|
||||
return render json: {}, status: 401 if channel.options[:token] != token
|
||||
# Use constant-time comparison to prevent timing attacks
|
||||
return render json: {}, status: 401 unless ActiveSupport::SecurityUtils.secure_compare(
|
||||
channel.options[:token].to_s,
|
||||
token.to_s
|
||||
)
|
||||
|
||||
# Handle group creation events
|
||||
if params[:event] == 'group_created'
|
||||
|
|
@ -218,38 +222,13 @@ class ChannelsCdrSignalController < ApplicationController
|
|||
Rails.logger.info "Channel ID: #{channel.id}"
|
||||
|
||||
begin
|
||||
# For group messages, search all tickets regardless of customer
|
||||
# since users may have duplicate phone numbers
|
||||
all_tickets = Ticket.where.not(state_id: state_ids)
|
||||
.order(updated_at: :desc)
|
||||
|
||||
Rails.logger.info "Found #{all_tickets.count} active tickets (searching all customers for group match)"
|
||||
|
||||
ticket = all_tickets.find do |t|
|
||||
begin
|
||||
has_preferences = t.preferences.is_a?(Hash)
|
||||
has_cdr_signal = has_preferences && t.preferences['cdr_signal'].is_a?(Hash)
|
||||
has_channel_id = has_preferences && t.preferences['channel_id'] == channel.id
|
||||
|
||||
if has_cdr_signal && has_channel_id
|
||||
stored_chat_id = t.preferences['cdr_signal']['chat_id']
|
||||
|
||||
Rails.logger.info " - stored_chat_id: #{stored_chat_id}"
|
||||
Rails.logger.info " - incoming_group_id: #{receiver_phone_number}"
|
||||
|
||||
matches = receiver_phone_number == stored_chat_id
|
||||
Rails.logger.info " - MATCH: #{matches}"
|
||||
|
||||
matches
|
||||
else
|
||||
Rails.logger.info "Ticket ##{t.number} has no cdr_signal preferences or wrong channel"
|
||||
false
|
||||
end
|
||||
rescue => e
|
||||
Rails.logger.error "Error checking ticket #{t.id}: #{e.message}"
|
||||
false
|
||||
end
|
||||
end
|
||||
# Use PostgreSQL JSONB queries to efficiently search preferences without loading all tickets into memory
|
||||
# This prevents DoS attacks from memory exhaustion
|
||||
ticket = Ticket.where.not(state_id: state_ids)
|
||||
.where("preferences->>'channel_id' = ?", channel.id.to_s)
|
||||
.where("preferences->'cdr_signal'->>'chat_id' = ?", receiver_phone_number)
|
||||
.order(updated_at: :desc)
|
||||
.first
|
||||
|
||||
if ticket
|
||||
Rails.logger.info "=== FOUND MATCHING TICKET BY GROUP ID: ##{ticket.number} ==="
|
||||
|
|
@ -441,14 +420,13 @@ class ChannelsCdrSignalController < ApplicationController
|
|||
end
|
||||
|
||||
# Find ticket(s) with this group_id in preferences
|
||||
# Search all active tickets for matching group
|
||||
# Use PostgreSQL JSONB queries for efficient lookup (prevents DoS from loading all tickets)
|
||||
state_ids = Ticket::State.where(name: %w[closed merged removed]).pluck(:id)
|
||||
|
||||
ticket = Ticket.where.not(state_id: state_ids).find do |t|
|
||||
t.preferences.is_a?(Hash) &&
|
||||
t.preferences['cdr_signal'].is_a?(Hash) &&
|
||||
t.preferences['cdr_signal']['chat_id'] == params[:group_id]
|
||||
end
|
||||
ticket = Ticket.where.not(state_id: state_ids)
|
||||
.where("preferences->'cdr_signal'->>'chat_id' = ?", params[:group_id])
|
||||
.order(updated_at: :desc)
|
||||
.first
|
||||
|
||||
unless ticket
|
||||
Rails.logger.warn "Signal group member joined: Ticket not found for group_id #{params[:group_id]}"
|
||||
|
|
@ -456,11 +434,22 @@ class ChannelsCdrSignalController < ApplicationController
|
|||
return
|
||||
end
|
||||
|
||||
# Check if the member who joined matches the original recipient
|
||||
original_recipient = ticket.preferences.dig('cdr_signal', 'original_recipient')
|
||||
member_phone = params[:member_phone]
|
||||
# Idempotency check: if already marked as joined, skip update and return success
|
||||
# This prevents unnecessary database writes when the cron job sends duplicate notifications
|
||||
if ticket.preferences.dig('cdr_signal', 'group_joined') == true
|
||||
Rails.logger.debug "Signal group member #{params[:member_phone]} already marked as joined for group #{params[:group_id]} ticket #{ticket.id}, skipping update"
|
||||
render json: {
|
||||
success: true,
|
||||
ticket_id: ticket.id,
|
||||
ticket_number: ticket.number,
|
||||
group_joined: true,
|
||||
already_joined: true
|
||||
}, status: :ok
|
||||
return
|
||||
end
|
||||
|
||||
# Update group_joined flag
|
||||
member_phone = params[:member_phone]
|
||||
ticket.preferences[:cdr_signal][:group_joined] = true
|
||||
ticket.preferences[:cdr_signal][:group_joined_at] = params[:timestamp] if params[:timestamp].present?
|
||||
ticket.preferences[:cdr_signal][:group_joined_by] = member_phone
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue