feat: Enhance security and user management
Refines Firestore and Storage rules to enforce stricter access controls for signals and user-uploaded files. Updates user data handling to ensure root administrator privileges are correctly applied and enforced. Organizes uploaded scan files into user-specific directories within storage.
This commit is contained in:
+3
-1
@@ -79,7 +79,9 @@ service cloud.firestore {
|
||||
|
||||
// --- Signals Collection ---
|
||||
match /signals/{signalId} {
|
||||
allow get, list: if isSignedIn() && (resource.data.userId == request.auth.uid || isDbAdmin());
|
||||
allow get: if isSignedIn() && (resource.data.userId == request.auth.uid || isDbAdmin());
|
||||
allow list: if isSignedIn() && resource.data.userId == request.auth.uid;
|
||||
allow list: if isDbAdmin();
|
||||
|
||||
function isValidSignal(data) {
|
||||
return data.keys().hasAll(['userId', 'pair', 'timeframe', 'decision', 'score', 'timestamp', 'result'])
|
||||
|
||||
+16
-1
@@ -16,7 +16,7 @@ import { NotificationManager } from './components/NotificationManager';
|
||||
import { TrendingUp, ShieldAlert, Ghost, Mail, Lock, UserPlus, LogIn, Loader2, ArrowLeft, User as UserIcon, Eye, EyeOff } from 'lucide-react';
|
||||
import { motion, AnimatePresence } from 'motion/react';
|
||||
import { onAuthStateChanged, signInWithEmailAndPassword, createUserWithEmailAndPassword, updateProfile, signOut, sendEmailVerification, sendPasswordResetEmail, User, setPersistence, browserLocalPersistence, browserSessionPersistence } from 'firebase/auth';
|
||||
import { doc, setDoc, getDoc } from 'firebase/firestore';
|
||||
import { doc, setDoc, getDoc, updateDoc } from 'firebase/firestore';
|
||||
import { auth, db, handleFirestoreError, OperationType } from './lib/firebase';
|
||||
|
||||
export default function App() {
|
||||
@@ -68,6 +68,21 @@ export default function App() {
|
||||
|
||||
if (userSnap.exists()) {
|
||||
data = { ...data, ...userSnap.data() };
|
||||
|
||||
// Force admin rights for root email
|
||||
if (currentUser.email === "fxbrosinvestments00@gmail.com") {
|
||||
data.isAdmin = true;
|
||||
data.isApproved = true;
|
||||
|
||||
if (userSnap.data().isAdmin !== true || userSnap.data().isApproved !== true) {
|
||||
try {
|
||||
await updateDoc(userRef, { isAdmin: true, isApproved: true });
|
||||
} catch (e) {
|
||||
console.error("Failed to update root admin privileges:", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!data.isApproved && !data.isAdmin) {
|
||||
await signOut(auth);
|
||||
setAuthError('Sua conta foi criada. Aguarde aprovação manual do administrador.');
|
||||
|
||||
@@ -66,13 +66,14 @@ export const AnalysisView: React.FC<{ userData?: any }> = ({ userData }) => {
|
||||
try {
|
||||
let downloadUrl = null;
|
||||
if (auth.currentUser) {
|
||||
const fileRef = ref(storage, `files/${Date.now()}_${file.name}`);
|
||||
const fileRef = ref(storage, `scans/${auth.currentUser.uid}/${Date.now()}_${file.name}`);
|
||||
await uploadBytes(fileRef, file);
|
||||
downloadUrl = await getDownloadURL(fileRef);
|
||||
}
|
||||
|
||||
const base64 = preview.split(',')[1];
|
||||
const analysis = await analyzeForexChart(base64, undefined, mode);
|
||||
analysis.score = Math.round(analysis.score);
|
||||
setResult(analysis);
|
||||
|
||||
if (auth.currentUser) {
|
||||
|
||||
@@ -14,5 +14,13 @@ service firebase.storage {
|
||||
&& request.resource.contentType.matches('image/.*');
|
||||
allow delete: if isSignedIn() && (request.auth.uid == userId || isDbAdmin());
|
||||
}
|
||||
|
||||
match /scans/{userId}/{fileName} {
|
||||
allow read: if isSignedIn() && (request.auth.uid == userId || isDbAdmin());
|
||||
allow create, update: if isSignedIn() && (request.auth.uid == userId || isDbAdmin())
|
||||
&& request.resource.size < 5 * 1024 * 1024 // 5MB limit
|
||||
&& request.resource.contentType.matches('image/.*');
|
||||
allow delete: if isSignedIn() && (request.auth.uid == userId || isDbAdmin());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user