rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { // Global Safety net default-deny catch-all match /{document=**} { allow read, write: if false; } // Hardened helper functions for static verification (denial of wallet guard) function isValidId(id) { return id is string && id.size() <= 128 && id.matches('^[a-zA-Z0-9_-]+$'); } function incoming() { return request.resource.data; } function existing() { return resource.data; } // High fidelity schema assertion helper for Tire Products function isValidTireProduct(data) { return data.keys().hasAll(['id', 'name', 'brand', 'size', 'feature', 'price', 'badge', 'segment', 'image', 'description']) && data.keys().size() == 10 && data.id is string && data.id.size() <= 128 && data.name is string && data.name.size() <= 128 && data.brand is string && data.brand.size() <= 128 && data.size is string && data.size.size() <= 64 && data.feature is string && data.feature.size() <= 256 && (data.price is int || data.price is float) && data.price >= 0 && data.badge is string && data.badge.size() <= 128 && data.segment is string && (data.segment == 'hot' || data.segment == 'new' || data.segment == 'famous') && data.image is string && data.image.size() <= 1024 && data.description is string && data.description.size() <= 4096; } // Modern High fidelity schema helper for the requested "products" collection function isValidProduct(data) { return data.name is string && data.name.size() <= 128 && data.brand is string && data.brand.size() <= 128 && data.size is string && data.size.size() <= 64 && (data.price is int || data.price is float) && data.price >= 0 && data.category is string && (data.category == 'hot-selling' || data.category == 'new-brands' || data.category == 'famous') && (data.stock is int || data.stock is float) && data.stock >= 0 && data.feature is string && data.feature.size() <= 256 && data.imageUrl is string && data.imageUrl.size() <= 1024; } // High fidelity schema assertion helper for User Testimonials function isValidUserReview(data) { return data.keys().hasAll(['name', 'rating', 'text', 'date', 'initials']) && data.keys().size() == 5 && data.name is string && data.name.size() <= 128 && data.rating is int && data.rating >= 1 && data.rating <= 5 && data.text is string && data.text.size() <= 4096 && data.date is string && data.date.size() <= 128 && data.initials is string && data.initials.size() <= 16; } // High fidelity schema assertion helper for Visitor Analytics function isValidVisitorLog(data) { return data.keys().hasAll(['sessionId', 'userAgent', 'platform', 'language', 'pagePath', 'timestamp']) && data.keys().size() == 6 && data.sessionId is string && data.sessionId.size() <= 256 && data.userAgent is string && data.userAgent.size() <= 1024 && data.platform is string && data.platform.size() <= 128 && data.language is string && data.language.size() <= 64 && data.pagePath is string && data.pagePath.size() <= 256 && data.timestamp is timestamp && data.timestamp == request.time; } // High fidelity schema assertion helper for Newsletter Subscribers function isValidSubscriber(data) { return data.keys().hasAll(['email', 'createdAt']) && data.keys().size() == 2 && data.email is string && data.email.size() <= 256 && data.email.matches('^[^@]+@[^@]+\\.[^@]+$') && data.createdAt is timestamp && data.createdAt == request.time; } // Hardened constraints for the /products/ collection (Public read, authenticated write or seed prefix) match /products/{productId} { allow read: if true; allow create: if (request.auth != null || productId.startsWith('seed-')) && isValidId(productId) && isValidProduct(incoming()); allow update: if request.auth != null && isValidId(productId) && isValidProduct(incoming()); allow delete: if request.auth != null && isValidId(productId); } // Allow public read on the system connectivity check path match /test/connection { allow read: if true; } // Hardened constraints for the /tyres/ collection match /tyres/{tyreId} { allow read: if true; allow create, update: if isValidId(tyreId) && isValidTireProduct(incoming()); allow delete: if isValidId(tyreId); } // Hardened constraints for the /reviews/ collection match /reviews/{reviewId} { allow read: if true; allow create: if isValidId(reviewId) && isValidUserReview(incoming()); allow update, delete: if false; // Reviews are write-once append-only } // Hardened constraints for the /visitors/ collection match /visitors/{visitorId} { allow read: if request.auth != null; // Admin-only read for visitor stats allow create: if isValidId(visitorId) && isValidVisitorLog(incoming()); allow update, delete: if false; // Visitor logs are immutable } // Hardened constraints for the /subscribers/ collection (Public sign up, Admin-only read) match /subscribers/{subscriberId} { allow read: if request.auth != null; // Admin can view mailing list allow create: if isValidId(subscriberId) && isValidSubscriber(incoming()); allow update, delete: if false; // Newsletter entries are append-only/immutable } } }