CopyBee
Depósito y difusor instantáneo de configuraciones seguras. Copia con un solo clic el conjunto canónico de reglas de seguridad de Firestore (RBAC, propietarios y bloqueo total administrativo) listas para producción.
CANONICAL // FIRESTORE_SECURITY_SPEC_V2
RULES_VERSION = '2'
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// ===============================================================
// FUNCIONES AUXILIARES DE SEGURIDAD (RBAC Y PROPIEDAD)
// ===============================================================
function isAuthenticated() {
return request.auth != null;
}
// Comprueba si el usuario tiene custom claims de admin o rol 'admin' en su documento de usuario
function isAdmin() {
return isAuthenticated() && (
request.auth.token.admin == true ||
(exists(/databases/$(database)/documents/users/$(request.auth.uid)) &&
get(/databases/$(database)/documents/users/$(request.auth.uid)).data.get('role', '') == 'admin')
);
}
function isOwner(userId) {
return isAuthenticated() && request.auth.uid == userId;
}
// ===============================================================
// REGLAS ESPECÍFICAS POR COLECCIÓN
// ===============================================================
// 0. CLAVES SECRETAS DE ACCESO ADMINISTRATIVO
// Bloqueo total desde el cliente/navegador.
// Solo accesible por el servidor backend (Firebase Admin SDK).
match /claves/{docId} {
allow read, write: if false;
}
match /clavesadmin/{docId} {
allow read, write: if false;
}
// 1. USUARIOS Y SU INFORMACIÓN PRIVADA
match /users/{userId} {
allow read: if isOwner(userId) || isAdmin();
// Un usuario solo puede registrarse a sí mismo y no puede auto-asignarse rol admin
allow create: if isOwner(userId) && request.resource.data.get('role', 'user') != 'admin';
// Puede actualizar sus datos personales pero no auto-escalar privilegios a admin
allow update: if (isOwner(userId) && request.resource.data.get('role', 'user') == resource.data.get('role', 'user')) || isAdmin();
allow delete: if isAdmin();
// Subcolecciones privadas del usuario (carrito, direcciones, métodos de pago, favoritos)
match /cartItems/{itemId} {
allow read, write: if isOwner(userId) || isAdmin();
}
match /addresses/{addressId} {
allow read, write: if isOwner(userId) || isAdmin();
}
match /paymentMethods/{methodId} {
allow read, write: if isOwner(userId) || isAdmin();
}
match /wishlist/{itemId} {
allow read, write: if isOwner(userId) || isAdmin();
}
}
// 2. PRODUCTOS Y VARIANTES
match /products/{productId} {
// Lectura pública para cualquier visitante de la tienda
allow read: if true;
// Modificaciones y gestión de catálogo restringidas al administrador
allow write: if isAdmin();
match /variants/{variantId} {
allow read: if true;
allow write: if isAdmin();
}
// Reseñas de productos
match /reviews/{reviewId} {
allow read: if true;
allow create: if isAuthenticated();
allow update, delete: if isAdmin();
}
}
// 3. CATEGORÍAS
match /categories/{categoryId} {
allow read: if true;
allow write: if isAdmin();
}
// 4. TRADUCCIONES E IDIOMAS (i18n)
match /translations/{translationId} {
allow read: if true;
allow write: if isAdmin();
}
// 5. PEDIDOS (ORDERS)
match /orders/{orderId} {
// El cliente solo puede leer sus propios pedidos; el administrador puede ver todos
allow read: if isAdmin() || (isAuthenticated() && resource.data.uid == request.auth.uid);
allow create: if isAuthenticated() && request.resource.data.uid == request.auth.uid;
allow update, delete: if isAdmin();
}
// 6. CÓDIGOS DE PROMOCIÓN Y DESCUENTOS
match /promotions/{promoId} {
allow read: if true;
allow write: if isAdmin();
}
// 7. AJUSTES GLOBALES Y CONFIGURACIÓN DE LA TIENDA
match /settings/{settingId} {
allow read: if true;
allow write: if isAdmin();
}
// 8. PÁGINAS CMS DEL EDITOR VISUAL (home, about, catalog)
match /pages/{pageId} {
allow read: if true;
allow write: if isAdmin();
}
// ===============================================================
// BLOQUEO POR DEFECTO PARA CUALQUIER OTRA RUTA
// ===============================================================
match /{document=**} {
allow read, write: if false;
}
}
}