mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-23 18:11:12 -05:00
Fix SECURITY DEFINER on filtered_profiles view
This commit is contained in:
@@ -2785,26 +2785,26 @@ export type Database = {
|
|||||||
username: string | null
|
username: string | null
|
||||||
}
|
}
|
||||||
Insert: {
|
Insert: {
|
||||||
avatar_image_id?: string | null
|
avatar_image_id?: never
|
||||||
avatar_url?: string | null
|
avatar_url?: never
|
||||||
banned?: boolean | null
|
banned?: never
|
||||||
bio?: string | null
|
bio?: never
|
||||||
coaster_count?: number | null
|
coaster_count?: never
|
||||||
created_at?: string | null
|
created_at?: string | null
|
||||||
date_of_birth?: string | null
|
date_of_birth?: never
|
||||||
display_name?: string | null
|
display_name?: string | null
|
||||||
home_park_id?: string | null
|
home_park_id?: never
|
||||||
id?: string | null
|
id?: string | null
|
||||||
location_id?: string | null
|
location_id?: never
|
||||||
park_count?: number | null
|
park_count?: never
|
||||||
personal_location?: string | null
|
personal_location?: never
|
||||||
preferred_language?: string | null
|
preferred_language?: string | null
|
||||||
preferred_pronouns?: string | null
|
preferred_pronouns?: never
|
||||||
privacy_level?: string | null
|
privacy_level?: string | null
|
||||||
reputation_score?: number | null
|
reputation_score?: never
|
||||||
review_count?: number | null
|
review_count?: never
|
||||||
ride_count?: number | null
|
ride_count?: never
|
||||||
show_pronouns?: boolean | null
|
show_pronouns?: never
|
||||||
theme_preference?: string | null
|
theme_preference?: string | null
|
||||||
timezone?: string | null
|
timezone?: string | null
|
||||||
updated_at?: string | null
|
updated_at?: string | null
|
||||||
@@ -2812,48 +2812,33 @@ export type Database = {
|
|||||||
username?: string | null
|
username?: string | null
|
||||||
}
|
}
|
||||||
Update: {
|
Update: {
|
||||||
avatar_image_id?: string | null
|
avatar_image_id?: never
|
||||||
avatar_url?: string | null
|
avatar_url?: never
|
||||||
banned?: boolean | null
|
banned?: never
|
||||||
bio?: string | null
|
bio?: never
|
||||||
coaster_count?: number | null
|
coaster_count?: never
|
||||||
created_at?: string | null
|
created_at?: string | null
|
||||||
date_of_birth?: string | null
|
date_of_birth?: never
|
||||||
display_name?: string | null
|
display_name?: string | null
|
||||||
home_park_id?: string | null
|
home_park_id?: never
|
||||||
id?: string | null
|
id?: string | null
|
||||||
location_id?: string | null
|
location_id?: never
|
||||||
park_count?: number | null
|
park_count?: never
|
||||||
personal_location?: string | null
|
personal_location?: never
|
||||||
preferred_language?: string | null
|
preferred_language?: string | null
|
||||||
preferred_pronouns?: string | null
|
preferred_pronouns?: never
|
||||||
privacy_level?: string | null
|
privacy_level?: string | null
|
||||||
reputation_score?: number | null
|
reputation_score?: never
|
||||||
review_count?: number | null
|
review_count?: never
|
||||||
ride_count?: number | null
|
ride_count?: never
|
||||||
show_pronouns?: boolean | null
|
show_pronouns?: never
|
||||||
theme_preference?: string | null
|
theme_preference?: string | null
|
||||||
timezone?: string | null
|
timezone?: string | null
|
||||||
updated_at?: string | null
|
updated_at?: string | null
|
||||||
user_id?: string | null
|
user_id?: string | null
|
||||||
username?: string | null
|
username?: string | null
|
||||||
}
|
}
|
||||||
Relationships: [
|
Relationships: []
|
||||||
{
|
|
||||||
foreignKeyName: "profiles_home_park_id_fkey"
|
|
||||||
columns: ["home_park_id"]
|
|
||||||
isOneToOne: false
|
|
||||||
referencedRelation: "parks"
|
|
||||||
referencedColumns: ["id"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
foreignKeyName: "profiles_location_id_fkey"
|
|
||||||
columns: ["location_id"]
|
|
||||||
isOneToOne: false
|
|
||||||
referencedRelation: "locations"
|
|
||||||
referencedColumns: ["id"]
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
moderation_sla_metrics: {
|
moderation_sla_metrics: {
|
||||||
Row: {
|
Row: {
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
-- Drop and recreate filtered_profiles view without SECURITY DEFINER
|
||||||
|
-- This view applies field-level privacy using security definer functions
|
||||||
|
-- but the view itself should NOT be security definer
|
||||||
|
DROP VIEW IF EXISTS public.filtered_profiles;
|
||||||
|
|
||||||
|
CREATE VIEW public.filtered_profiles AS
|
||||||
|
SELECT
|
||||||
|
p.id,
|
||||||
|
p.user_id,
|
||||||
|
p.username,
|
||||||
|
p.display_name,
|
||||||
|
p.privacy_level,
|
||||||
|
p.created_at,
|
||||||
|
p.updated_at,
|
||||||
|
-- Field-level privacy using security definer functions
|
||||||
|
CASE
|
||||||
|
WHEN can_view_profile_field(COALESCE(auth.uid(), '00000000-0000-0000-0000-000000000000'::uuid), p.user_id, 'bio') THEN p.bio
|
||||||
|
ELSE NULL
|
||||||
|
END AS bio,
|
||||||
|
CASE
|
||||||
|
WHEN can_view_profile_field(COALESCE(auth.uid(), '00000000-0000-0000-0000-000000000000'::uuid), p.user_id, 'avatar_url') THEN p.avatar_url
|
||||||
|
ELSE NULL
|
||||||
|
END AS avatar_url,
|
||||||
|
CASE
|
||||||
|
WHEN can_view_profile_field(COALESCE(auth.uid(), '00000000-0000-0000-0000-000000000000'::uuid), p.user_id, 'avatar_image_id') THEN p.avatar_image_id
|
||||||
|
ELSE NULL
|
||||||
|
END AS avatar_image_id,
|
||||||
|
CASE
|
||||||
|
WHEN can_view_profile_field(COALESCE(auth.uid(), '00000000-0000-0000-0000-000000000000'::uuid), p.user_id, 'preferred_pronouns') THEN p.preferred_pronouns
|
||||||
|
ELSE NULL
|
||||||
|
END AS preferred_pronouns,
|
||||||
|
CASE
|
||||||
|
WHEN can_view_profile_field(COALESCE(auth.uid(), '00000000-0000-0000-0000-000000000000'::uuid), p.user_id, 'preferred_pronouns') THEN p.show_pronouns
|
||||||
|
ELSE false
|
||||||
|
END AS show_pronouns,
|
||||||
|
CASE
|
||||||
|
WHEN can_view_profile_field(COALESCE(auth.uid(), '00000000-0000-0000-0000-000000000000'::uuid), p.user_id, 'personal_location') THEN p.personal_location
|
||||||
|
ELSE NULL
|
||||||
|
END AS personal_location,
|
||||||
|
CASE
|
||||||
|
WHEN can_view_profile_field(COALESCE(auth.uid(), '00000000-0000-0000-0000-000000000000'::uuid), p.user_id, 'location_id') THEN p.location_id
|
||||||
|
ELSE NULL
|
||||||
|
END AS location_id,
|
||||||
|
CASE
|
||||||
|
WHEN can_view_profile_field(COALESCE(auth.uid(), '00000000-0000-0000-0000-000000000000'::uuid), p.user_id, 'home_park_id') THEN p.home_park_id
|
||||||
|
ELSE NULL
|
||||||
|
END AS home_park_id,
|
||||||
|
CASE
|
||||||
|
WHEN can_view_profile_field(COALESCE(auth.uid(), '00000000-0000-0000-0000-000000000000'::uuid), p.user_id, 'date_of_birth') THEN p.date_of_birth
|
||||||
|
ELSE NULL
|
||||||
|
END AS date_of_birth,
|
||||||
|
p.timezone,
|
||||||
|
p.preferred_language,
|
||||||
|
p.theme_preference,
|
||||||
|
CASE
|
||||||
|
WHEN can_view_profile_field(COALESCE(auth.uid(), '00000000-0000-0000-0000-000000000000'::uuid), p.user_id, 'ride_count') THEN p.ride_count
|
||||||
|
ELSE 0
|
||||||
|
END AS ride_count,
|
||||||
|
CASE
|
||||||
|
WHEN can_view_profile_field(COALESCE(auth.uid(), '00000000-0000-0000-0000-000000000000'::uuid), p.user_id, 'ride_count') THEN p.coaster_count
|
||||||
|
ELSE 0
|
||||||
|
END AS coaster_count,
|
||||||
|
CASE
|
||||||
|
WHEN can_view_profile_field(COALESCE(auth.uid(), '00000000-0000-0000-0000-000000000000'::uuid), p.user_id, 'ride_count') THEN p.park_count
|
||||||
|
ELSE 0
|
||||||
|
END AS park_count,
|
||||||
|
CASE
|
||||||
|
WHEN can_view_profile_field(COALESCE(auth.uid(), '00000000-0000-0000-0000-000000000000'::uuid), p.user_id, 'ride_count') THEN p.review_count
|
||||||
|
ELSE 0
|
||||||
|
END AS review_count,
|
||||||
|
CASE
|
||||||
|
WHEN can_view_profile_field(COALESCE(auth.uid(), '00000000-0000-0000-0000-000000000000'::uuid), p.user_id, 'ride_count') THEN p.reputation_score
|
||||||
|
ELSE 0
|
||||||
|
END AS reputation_score,
|
||||||
|
CASE
|
||||||
|
WHEN auth.uid() = p.user_id OR is_moderator(COALESCE(auth.uid(), '00000000-0000-0000-0000-000000000000'::uuid)) THEN p.banned
|
||||||
|
ELSE false
|
||||||
|
END AS banned
|
||||||
|
FROM public.profiles p
|
||||||
|
WHERE (NOT p.banned OR auth.uid() = p.user_id OR is_moderator(COALESCE(auth.uid(), '00000000-0000-0000-0000-000000000000'::uuid)))
|
||||||
|
AND (p.privacy_level = 'public' OR auth.uid() = p.user_id OR is_moderator(COALESCE(auth.uid(), '00000000-0000-0000-0000-000000000000'::uuid)));
|
||||||
|
|
||||||
|
COMMENT ON VIEW public.filtered_profiles IS 'Profile view with field-level privacy controls. Uses security definer functions for permission checks but view itself respects querying user context.';
|
||||||
Reference in New Issue
Block a user