File size: 1,405 Bytes
a4fb0f8 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | -- Fix for Insecure Public Verification Policy
-- This migration replaces the broad 'is_completed = true' policy with a secure RPC-based lookup.
-- 1. Remove the insecure anon SELECT policy
DROP POLICY "Public verification of certificates" ON public.user_achievements;
-- 2. Implement secure RPC function for certificate verification
-- This function is SECURITY DEFINER to bypass RLS and perform the specific lookup.
CREATE OR REPLACE FUNCTION public.verify_certificate_token(token UUID, slug TEXT)
RETURNS TABLE (
user_id UUID,
user_display_name TEXT,
achievement_display_name TEXT,
completed_at TIMESTAMPTZ
)
LANGUAGE plpgsql
SECURITY DEFINER
AS $$
BEGIN
RETURN QUERY
SELECT
ua.user_id,
p.display_name as user_display_name,
ad.display_name as achievement_display_name,
ua.completed_at
FROM public.user_achievements ua
JOIN public.achievement_definitions ad ON ua.achievement_id = ad.id
LEFT JOIN public.profiles p ON ua.user_id = p.id
WHERE ua.verification_token = token
AND ad.slug = slug
AND ua.is_completed = true;
END;
$$;
-- 3. Add restrictive RLS policy to prevent direct anon access
-- This ensures that anon users cannot list achievements via SELECT * FROM user_achievements.
CREATE POLICY "Anon has no direct access to user_achievements"
ON public.user_achievements FOR SELECT
TO anon
USING (false);
|