Spaces:
Runtime error
Runtime error
File size: 3,604 Bytes
3125e5c | 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 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | -- ============================================================
-- Venorly — Supabase Güvenlik Migration
-- Çalıştırma: Supabase Dashboard > SQL Editor > New Query
-- ============================================================
-- ── 1. credits negatife düşemez constraint ──────────────────
-- Mevcut negatif değerleri önce 0'a çek (varsa)
UPDATE users SET credits = 0 WHERE credits < 0;
-- Constraint ekle
ALTER TABLE users
ADD CONSTRAINT credits_non_negative
CHECK (credits >= 0);
-- ── 2. consume_credit atomic fonksiyonu ─────────────────────
-- Race condition'ı önler: check + decrement tek transaction'da
-- Returns: TRUE = kredi düşüldü, FALSE = yetersiz kredi
CREATE OR REPLACE FUNCTION consume_credit(
p_clerk_id TEXT,
p_cost INTEGER
)
RETURNS BOOLEAN
LANGUAGE plpgsql
SECURITY DEFINER -- Fonksiyon sahibinin yetkisiyle çalışır
AS $$
DECLARE
rows_affected INTEGER;
BEGIN
UPDATE users
SET credits = credits - p_cost
WHERE clerk_id = p_clerk_id
AND credits >= p_cost;
GET DIAGNOSTICS rows_affected = ROW_COUNT;
RETURN rows_affected > 0;
END;
$$;
-- Sadece authenticated kullanıcılar çağırabilsin
REVOKE ALL ON FUNCTION consume_credit FROM PUBLIC;
GRANT EXECUTE ON FUNCTION consume_credit TO authenticated;
GRANT EXECUTE ON FUNCTION consume_credit TO service_role;
-- ── 3. scans tablosuna user_id kolonu ───────────────────────
-- IDOR fix için gerekli: hangi scan kime ait?
-- Kolon yoksa ekle (varsa hata vermez)
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_name = 'scans'
AND column_name = 'user_id'
) THEN
ALTER TABLE scans ADD COLUMN user_id TEXT;
COMMENT ON COLUMN scans.user_id IS 'Clerk sub / Supabase user id — ownership için';
END IF;
END $$;
-- Index ekle (ownership sorguları için)
CREATE INDEX IF NOT EXISTS idx_scans_user_id ON scans(user_id);
-- ── 4. Doğrulama sorguları ───────────────────────────────────
-- Migration'ı çalıştırdıktan sonra bu 3 sorguyu AYRI AYRI çalıştırıp
-- sonuçları kontrol edin (hepsini birden çalıştırmayın):
-- a) Constraint var mı? (PostgreSQL 12+ uyumlu)
SELECT conname,
pg_get_constraintdef(oid) AS constraint_def
FROM pg_constraint
WHERE conrelid = 'users'::regclass
AND conname = 'credits_non_negative';
-- Beklenen: 1 satır, constraint_def = "CHECK ((credits >= 0))"
-- b) Fonksiyon var mı?
SELECT proname,
prosecdef,
pg_get_functiondef(oid) AS func_def
FROM pg_proc
WHERE proname = 'consume_credit';
-- Beklenen: 1 satır, prosecdef = true
-- c) user_id kolonu var mı?
SELECT column_name, data_type, is_nullable
FROM information_schema.columns
WHERE table_name = 'scans'
AND column_name = 'user_id';
-- Beklenen: 1 satır, data_type = 'text'
-- ── 5. Mevcut scan'lere user_id backfill ────────────────────
-- Eğer Supabase Auth kullanıyorsanız ve usage_logs'ta eşleşme
-- varsa aşağıdaki query ile backfill yapabilirsiniz:
-- (Opsiyonel — yeni scan'ler zaten user_id ile kaydedilecek)
-- UPDATE scans s
-- SET user_id = ul.ip_address -- ip_address clerk_id olarak kullanılıyorsa
-- FROM usage_logs ul
-- WHERE ul.action_type = s.mode
-- AND s.user_id IS NULL
-- AND ul.created_at::date = s.created_at::date;
|