Skip to content

Commit fdcb149

Browse files
Add affiliate RLS policies
1 parent 0228245 commit fdcb149

2 files changed

Lines changed: 106 additions & 0 deletions

File tree

src/integrations/supabase/types.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,10 @@ export type Database = {
611611
Args: { integration_id: string; plain_token: string }
612612
Returns: undefined
613613
}
614+
log_affiliate_data_access: {
615+
Args: { access_type: string; affiliate_id: string }
616+
Returns: undefined
617+
}
614618
log_billing_access: {
615619
Args: { access_type: string; record_id: string }
616620
Returns: undefined
@@ -623,6 +627,10 @@ export type Database = {
623627
Args: { campaign_id: string; requesting_user_id?: string }
624628
Returns: boolean
625629
}
630+
validate_affiliate_data_access: {
631+
Args: { affiliate_id: string; requesting_user_id?: string }
632+
Returns: boolean
633+
}
626634
validate_billing_record_ownership: {
627635
Args: { record_id: string }
628636
Returns: boolean
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
-- Fix security vulnerability: Allow affiliates to access their own data
2+
-- This addresses the issue where affiliates couldn't see their own profile information
3+
4+
-- Add policy to allow affiliates to view their own data
5+
CREATE POLICY "Affiliates can view their own data"
6+
ON public.affiliates
7+
FOR SELECT
8+
USING (auth.uid() = user_id);
9+
10+
-- Add policy to allow affiliates to update their own basic profile data
11+
-- Note: Sensitive fields like commission_rate, tracking_code should only be updateable by campaign owners
12+
CREATE POLICY "Affiliates can update their own basic profile"
13+
ON public.affiliates
14+
FOR UPDATE
15+
USING (
16+
auth.uid() = user_id
17+
)
18+
WITH CHECK (
19+
auth.uid() = user_id
20+
);
21+
22+
-- Add security function to validate affiliate data access
23+
CREATE OR REPLACE FUNCTION public.validate_affiliate_data_access(affiliate_id uuid, requesting_user_id uuid DEFAULT auth.uid())
24+
RETURNS boolean
25+
LANGUAGE plpgsql
26+
SECURITY DEFINER
27+
SET search_path TO 'public'
28+
AS $function$
29+
DECLARE
30+
affiliate_user_id uuid;
31+
campaign_owner_id uuid;
32+
BEGIN
33+
-- Get affiliate user_id and campaign owner
34+
SELECT a.user_id, c.user_id INTO affiliate_user_id, campaign_owner_id
35+
FROM affiliates a
36+
JOIN campaigns c ON c.id = a.campaign_id
37+
WHERE a.id = affiliate_id;
38+
39+
-- Allow access if user is the affiliate or campaign owner
40+
RETURN (requesting_user_id = affiliate_user_id OR requesting_user_id = campaign_owner_id);
41+
END;
42+
$function$;
43+
44+
-- Log security event for affiliate data access
45+
CREATE OR REPLACE FUNCTION public.log_affiliate_data_access(affiliate_id uuid, access_type text)
46+
RETURNS void
47+
LANGUAGE plpgsql
48+
SECURITY DEFINER
49+
SET search_path TO 'public'
50+
AS $function$
51+
BEGIN
52+
PERFORM public.log_security_event(
53+
'affiliate_data_access',
54+
auth.uid(),
55+
jsonb_build_object(
56+
'affiliate_id', affiliate_id,
57+
'access_type', access_type,
58+
'timestamp', now()
59+
)
60+
);
61+
END;
62+
$function$;
63+
64+
-- Create trigger to prevent affiliates from modifying sensitive fields
65+
CREATE OR REPLACE FUNCTION public.prevent_affiliate_sensitive_field_changes()
66+
RETURNS trigger
67+
LANGUAGE plpgsql
68+
SECURITY DEFINER
69+
SET search_path TO 'public'
70+
AS $function$
71+
DECLARE
72+
is_campaign_owner boolean;
73+
BEGIN
74+
-- Check if current user is the campaign owner
75+
SELECT EXISTS (
76+
SELECT 1 FROM campaigns
77+
WHERE id = NEW.campaign_id AND user_id = auth.uid()
78+
) INTO is_campaign_owner;
79+
80+
-- If not campaign owner, prevent changes to sensitive fields
81+
IF NOT is_campaign_owner THEN
82+
-- Preserve original values for sensitive fields
83+
NEW.commission_rate := OLD.commission_rate;
84+
NEW.tracking_code := OLD.tracking_code;
85+
NEW.campaign_id := OLD.campaign_id;
86+
NEW.stripe_account_id := OLD.stripe_account_id;
87+
NEW.stripe_account_status := OLD.stripe_account_status;
88+
END IF;
89+
90+
RETURN NEW;
91+
END;
92+
$function$;
93+
94+
-- Apply the trigger to affiliates table
95+
CREATE TRIGGER prevent_affiliate_sensitive_changes
96+
BEFORE UPDATE ON public.affiliates
97+
FOR EACH ROW
98+
EXECUTE FUNCTION public.prevent_affiliate_sensitive_field_changes();

0 commit comments

Comments
 (0)