Skip to content

Commit 949e7fd

Browse files
CayoPOliveiragabrieljablonski
authored andcommitted
fix: address PR #228 review feedback - strong params, guards, and safety fixes
1 parent 0cc9293 commit 949e7fd

File tree

12 files changed

+88
-31
lines changed

12 files changed

+88
-31
lines changed

app/controllers/api/v1/accounts/contacts/group_join_requests_controller.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,18 @@ def index
99

1010
def handle
1111
authorize @contact, :update?
12-
channel.handle_group_join_requests(@contact.identifier, params[:participants], params[:request_action])
12+
channel.handle_group_join_requests(@contact.identifier, handle_params[:participants], handle_params[:request_action])
1313
head :ok
1414
rescue Whatsapp::Providers::WhatsappBaileysService::ProviderUnavailableError => e
1515
render json: { error: e.message }, status: :unprocessable_entity
1616
end
1717

1818
private
1919

20+
def handle_params
21+
params.permit(:request_action, participants: [])
22+
end
23+
2024
def channel
2125
@channel ||= @contact.group_channel
2226
end

app/controllers/api/v1/accounts/contacts/group_members_controller.rb

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ def index
1111
.includes(:contact)
1212

1313
@total_count = base_query.count
14-
@page = (params[:page] || 1).to_i
15-
@per_page = (params[:per_page] || DEFAULT_PER_PAGE).to_i
14+
@page = [(params[:page] || 1).to_i, 1].max
15+
@per_page = (params[:per_page] || DEFAULT_PER_PAGE).to_i.clamp(1, 100)
1616
@inbox_phone_number = inbox_phone_number
1717

1818
paginated = base_query.order(role: :desc, id: :asc)
@@ -24,21 +24,25 @@ def index
2424

2525
def create
2626
authorize @contact, :update?
27+
participants = create_params[:participants]
28+
return render json: { error: 'participants_required' }, status: :unprocessable_entity if participants.blank?
2729

28-
channel.update_group_participants(@contact.identifier, format_participants(params[:participants]), 'add')
29-
add_group_members(params[:participants])
30+
channel.update_group_participants(@contact.identifier, format_participants(participants), 'add')
31+
add_group_members(participants)
3032
head :ok
3133
rescue Whatsapp::Providers::WhatsappBaileysService::ProviderUnavailableError => e
3234
render json: { error: e.message }, status: :unprocessable_entity
3335
end
3436

3537
def update
3638
authorize @contact, :update?
39+
role = update_params[:role]
40+
return render json: { error: 'invalid_role' }, status: :unprocessable_entity unless %w[admin member].include?(role)
3741

3842
member = group_members.find(params[:member_id])
39-
action = params[:role] == 'admin' ? 'promote' : 'demote'
43+
action = role == 'admin' ? 'promote' : 'demote'
4044
channel.update_group_participants(@contact.identifier, [jid_for_member(member)], action)
41-
member.update!(role: params[:role])
45+
member.update!(role: role)
4246
head :ok
4347
rescue Whatsapp::Providers::WhatsappBaileysService::GroupParticipantNotAllowedError
4448
render json: { error: 'group_creator_not_modifiable' }, status: :unprocessable_entity
@@ -71,6 +75,14 @@ def group_members
7175
GroupMember.where(group_contact: @contact)
7276
end
7377

78+
def create_params
79+
params.permit(participants: [])
80+
end
81+
82+
def update_params
83+
params.permit(:role)
84+
end
85+
7486
def channel
7587
@channel ||= @contact.group_channel
7688
end
@@ -112,7 +124,9 @@ def jid_for_member(member)
112124
def add_group_members(phone_numbers)
113125
inbox = @contact.contact_inboxes.first&.inbox
114126
Array(phone_numbers).each do |phone|
115-
normalized = phone.start_with?('+') ? phone : "+#{phone}"
127+
normalized = normalize_phone(phone)
128+
next if normalized.blank?
129+
116130
contact_inbox = ::ContactInboxWithContactBuilder.new(
117131
source_id: normalized.delete('+'),
118132
inbox: inbox,
@@ -124,4 +138,11 @@ def add_group_members(phone_numbers)
124138
member.update!(role: :member, is_active: true) unless member.persisted? && member.is_active?
125139
end
126140
end
141+
142+
def normalize_phone(phone)
143+
cleaned = phone.to_s.strip
144+
return nil if cleaned.blank?
145+
146+
cleaned.start_with?('+') ? cleaned : "+#{cleaned}"
147+
end
127148
end

app/controllers/api/v1/accounts/contacts/group_metadata_controller.rb

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,27 @@
11
class Api::V1::Accounts::Contacts::GroupMetadataController < Api::V1::Accounts::Contacts::BaseController
22
def update
33
authorize @contact, :update?
4-
update_subject if params[:subject].present?
5-
update_description if params[:description].present?
4+
update_subject if metadata_params[:subject].present?
5+
update_description if metadata_params[:description].present?
66
render json: { id: @contact.id, name: @contact.name, additional_attributes: @contact.additional_attributes }
77
rescue Whatsapp::Providers::WhatsappBaileysService::ProviderUnavailableError => e
88
render json: { error: e.message }, status: :unprocessable_entity
99
end
1010

1111
private
1212

13+
def metadata_params
14+
params.permit(:subject, :description)
15+
end
16+
1317
def update_subject
14-
channel.update_group_subject(@contact.identifier, params[:subject])
15-
@contact.update!(name: params[:subject])
18+
channel.update_group_subject(@contact.identifier, metadata_params[:subject])
19+
@contact.update!(name: metadata_params[:subject])
1620
end
1721

1822
def update_description
19-
channel.update_group_description(@contact.identifier, params[:description])
20-
attrs = @contact.additional_attributes.merge('description' => params[:description])
23+
channel.update_group_description(@contact.identifier, metadata_params[:description])
24+
attrs = @contact.additional_attributes.merge('description' => metadata_params[:description])
2125
@contact.update!(additional_attributes: attrs)
2226
end
2327

app/controllers/api/v1/accounts/contacts/group_settings_controller.rb

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,39 @@ def leave
1010

1111
def update
1212
authorize @contact, :update?
13-
channel.group_setting_update(@contact.identifier, params[:setting])
14-
update_contact_setting(params[:setting])
13+
setting = setting_params[:setting]
14+
valid_settings = %w[announcement not_announcement locked unlocked]
15+
return render json: { error: 'invalid_setting' }, status: :unprocessable_entity unless setting.in?(valid_settings)
16+
17+
channel.group_setting_update(@contact.identifier, setting)
18+
update_contact_setting(setting)
1519
head :ok
1620
rescue Whatsapp::Providers::WhatsappBaileysService::ProviderUnavailableError => e
1721
render json: { error: e.message }, status: :unprocessable_entity
1822
end
1923

2024
def toggle_join_approval
2125
authorize @contact, :update?
22-
channel.group_join_approval_mode(@contact.identifier, params[:mode])
23-
update_contact_attribute('join_approval_mode', params[:mode] == 'on')
26+
mode = join_approval_params[:mode]
27+
return render json: { error: 'invalid_mode' }, status: :unprocessable_entity unless mode.in?(%w[on off])
28+
29+
channel.group_join_approval_mode(@contact.identifier, mode)
30+
update_contact_attribute('join_approval_mode', mode == 'on')
2431
head :ok
2532
rescue Whatsapp::Providers::WhatsappBaileysService::ProviderUnavailableError => e
2633
render json: { error: e.message }, status: :unprocessable_entity
2734
end
2835

2936
private
3037

38+
def setting_params
39+
params.permit(:setting)
40+
end
41+
42+
def join_approval_params
43+
params.permit(:mode)
44+
end
45+
3146
def channel
3247
@channel ||= @contact.group_channel
3348
end

app/controllers/api/v1/accounts/groups_controller.rb

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
class Api::V1::Accounts::GroupsController < Api::V1::Accounts::BaseController
22
def create
3-
inbox = Current.account.inboxes.find_by(id: params[:inbox_id])
3+
inbox = Current.account.inboxes.find_by(id: group_params[:inbox_id])
44
return render json: { error: 'Access Denied' }, status: :forbidden unless inbox_accessible?(inbox)
55

66
result = Groups::CreateService.new(
77
inbox: inbox,
8-
subject: params[:subject],
9-
participants: Array(params[:participants])
8+
subject: group_params[:subject],
9+
participants: Array(group_params[:participants])
1010
).perform
1111

1212
render json: result
@@ -16,6 +16,10 @@ def create
1616

1717
private
1818

19+
def group_params
20+
params.permit(:inbox_id, :subject, participants: [])
21+
end
22+
1923
def inbox_accessible?(inbox)
2024
inbox.present? && Current.user.assigned_inboxes.exists?(id: inbox.id) && inbox.channel.try(:allow_group_creation?)
2125
end

app/javascript/dashboard/helper/actionCable.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ class ActionCableConnector extends BaseActionCableConnector {
9393
const pendingJid = pendingGroupNavigation.consume();
9494
if (pendingJid && data.meta?.sender?.identifier === pendingJid) {
9595
emitter.emit(BUS_EVENTS.NAVIGATE_TO_GROUP, { conversationId: data.id });
96+
} else if (pendingJid) {
97+
pendingGroupNavigation.set(pendingJid);
9698
}
9799
};
98100

app/services/groups/create_service.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ class Groups::CreateService
33

44
def perform
55
group_data = channel.create_group(subject, format_participants)
6-
group_jid = group_data[:id]
6+
group_jid = group_data&.dig(:id)
77
raise Whatsapp::Providers::WhatsappBaileysService::ProviderUnavailableError, 'Group JID missing from response' if group_jid.blank?
88

99
{ group_jid: group_jid }

app/services/whatsapp/baileys_handlers/concerns/group_contact_message_handler.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ def baileys_sender_phone
188188

189189
jid_part = sender_jid.split('@').first
190190
parts = jid_part.split(':')
191-
parts.first if parts.first.match?(/^\d+$/) && parts.length > 1
191+
parts.first if parts.first.match?(/^\d+$/)
192192
end
193193

194194
def baileys_sender_lid

app/services/whatsapp/baileys_handlers/concerns/group_stub_message_handler.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ def resolve_membership_request_contact_name(stub_params)
9090
phone = extract_jid_user(participant_data['pn'])
9191

9292
find_contact_display_name(lid, phone) || format_fallback_name(lid, phone)
93-
rescue JSON::ParserError
93+
rescue JSON::ParserError, TypeError
9494
extract_jid_user(@raw_message[:key][:participant])
9595
end
9696

app/services/whatsapp/baileys_handlers/group_participants_update.rb

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,10 @@ module Whatsapp::BaileysHandlers::GroupParticipantsUpdate
77

88
def process_group_participants_update
99
data = processed_params[:data]
10-
group_jid = data[:id]
11-
author = data[:author]
12-
action = data[:action]
13-
participants = data[:participants]
10+
return if data.blank?
1411

15-
return if group_jid.blank? || action.blank? || participants.blank?
12+
group_jid, author, action, participants = data.values_at(:id, :author, :action, :participants)
13+
return unless valid_participant_update?(group_jid, action, participants)
1614

1715
with_contact_lock(group_jid) do
1816
group_contact_inbox = find_or_create_group_contact_inbox_by_jid(group_jid)
@@ -29,6 +27,10 @@ def process_group_participants_update
2927
end
3028
end
3129

30+
def valid_participant_update?(group_jid, action, participants)
31+
group_jid.present? && action.present? && participants.present? && action.in?(%w[add remove promote demote])
32+
end
33+
3234
def apply_participant_action(action, group_contact, contact)
3335
case action
3436
when 'add'

0 commit comments

Comments
 (0)