1+ -- Drop the overly broad existing policy
2+ DROP POLICY IF EXISTS " Users can view their billing records" ON public .billing_records ;
3+
4+ -- Create more granular and secure RLS policies for billing_records
5+ CREATE POLICY " Users can view their own billing records"
6+ ON public .billing_records
7+ FOR SELECT
8+ TO authenticated
9+ USING (auth .uid () = user_id);
10+
11+ -- System can create billing records (for automated processing)
12+ CREATE POLICY " System can create billing records"
13+ ON public .billing_records
14+ FOR INSERT
15+ TO authenticated
16+ WITH CHECK (auth .uid () = user_id);
17+
18+ -- Only allow updates to specific non-sensitive fields and only by record owner
19+ CREATE POLICY " Users can update limited billing record fields"
20+ ON public .billing_records
21+ FOR UPDATE
22+ TO authenticated
23+ USING (auth .uid () = user_id)
24+ WITH CHECK (
25+ auth .uid () = user_id AND
26+ -- Prevent modification of critical financial data
27+ OLD .total_revenue = NEW .total_revenue AND
28+ OLD .commission_amount = NEW .commission_amount AND
29+ OLD .fee_amount = NEW .fee_amount AND
30+ OLD .stripe_charge_id = NEW .stripe_charge_id AND
31+ OLD .campaign_id = NEW .campaign_id AND
32+ OLD .created_at = NEW .created_at
33+ );
34+
35+ -- No deletion of billing records for audit trail integrity
36+ CREATE POLICY " Billing records cannot be deleted"
37+ ON public .billing_records
38+ FOR DELETE
39+ TO authenticated
40+ USING (false);
41+
42+ -- Create security audit function for billing record access
43+ CREATE OR REPLACE FUNCTION public .log_billing_access(record_id uuid, access_type text )
44+ RETURNS void
45+ LANGUAGE plpgsql
46+ SECURITY DEFINER
47+ SET search_path = public
48+ AS $$
49+ BEGIN
50+ -- Log financial data access for security monitoring
51+ PERFORM public .log_security_event (
52+ ' billing_record_access' ,
53+ auth .uid (),
54+ jsonb_build_object(
55+ ' record_id' , record_id,
56+ ' access_type' , access_type,
57+ ' timestamp' , now()
58+ )
59+ );
60+ END;
61+ $$;
62+
63+ -- Create function to validate billing record ownership before sensitive operations
64+ CREATE OR REPLACE FUNCTION public .validate_billing_record_ownership(record_id uuid)
65+ RETURNS boolean
66+ LANGUAGE plpgsql
67+ SECURITY DEFINER
68+ SET search_path = public
69+ AS $$
70+ DECLARE
71+ record_owner uuid;
72+ BEGIN
73+ SELECT user_id INTO record_owner
74+ FROM billing_records
75+ WHERE id = record_id;
76+
77+ RETURN (record_owner = auth .uid ());
78+ END;
79+ $$;
0 commit comments