Ograniczanie dostępu dziecka / pola za pomocą reguł bezpieczeństwa

Piszę aplikację, która pozwala użytkownikom przesyłać nominacje, które są moderowane przed wyświetleniem innym użytkownikom. Wymaga to szeregu ograniczeń, których dotychczas nie udało mi się wdrożyć za pomocą reguł bezpieczeństwa:

Ukryj wszystkie nominacje, które jeszcze nie zostały zatwierdzoneUkryj prywatne pola przed przesłaniem (telefon, status zatwierdzenia, data utworzenia itp.)

Moje obecne zasady są następujące:

{
    "rules": {
        "nominations": {
            ".read": true,

            "$nominationId": {
                ".read": "data.child('state').val() == 'approved' || auth != null", // Only read approved nominations if not authenticated
                ".write": "!data.exists()", // Only allow new nominations to be created

                "phone": {
                    ".read": "auth != null" // Only allow authenticated users to read phone number
                },

                "state": {
                    ".read": "auth != null", // Only allow authenticated users to read approval state
                    ".write": "auth != null" // Only allow authenticated users to change state
                }
            }
        }
    }
}

Zasady dotyczące dzieci (np.$nomination) nie przeszkadza dziecku w przeczytaniu całego dziecka. Jeśli mnie słuchamchild_added nahttps://my.firebaseio.com/nominations z radością zwraca wszystkie dzieci i wszystkie ich dane, nawet przy zastosowaniu powyższych zasad bezpieczeństwa.

Moim obecnym pomysłem na obejście tego problemu jest zachowanie nazwy oddzielnego węzłaapproved i po prostu przesuwaj dane między listami, gdy ktoś zatwierdza lub odrzuca nominację, ale wydaje się, że jest to strasznie złamane podejście.

Aktualizacja

NastępującyMichael LehenbauerDoskonały komentarz Wprowadziłem pierwotny pomysł przy minimalnym wysiłku.

Nowa struktura danych wygląda następująco:

my-firebase
    |
    `- nominations
        |
        `- entries
        |   |
        |   `- private
        |   `- public
        |
        `- status
            |
            `- pending
            `- approved
            `- rejected

Każda nominacja jest przechowywana podentries z prywatnymi danymi, takimi jak numer telefonu, e-mail itp. podprivate i publicznie dostępne dane w ramachpublic.

Zaktualizowane zasady są następujące:

{
    "rules": {
        "nominations": {
            "entries": {
                "$id": {
                    ".write": "!data.exists()",

                    "public": {
                        ".read": true,
                    },

                    "private": {
                        ".read": "auth != null"
                    }
                }
            },

            "status": {
                "pending": {
                    ".read": "auth != null",

                    "$id": {
                        ".write": "root.child('nominations/entries').child($id).exists() && (auth != null || newData.val() == true)"
                    }
                },

                "approved": {
                    ".read": true,

                    "$id": {
                        ".write": "root.child('nominations/entries').child($id).exists() && auth != null"
                    }
                },


                "rejected": {
                    ".read": "auth != null",

                    "$id": {
                        ".write": "root.child('nominations/entries').child($id).exists() && auth != null"
                    }
                }
            }
        }
    }
}

A implementacja JavaScript:

var db = new Firebase('https://my.firebaseio.com')
var nominations = db.child('nominations')

var entries = nominations.child('entries')

var status = nominations.child('status')
var pending = status.child('pending')
var approved = status.child('approved')
var rejected = status.child('rejected')

// Create nomination via form input (not shown)
var createNomination = function() {
    var data = {
        public: {
            name: 'Foo',
            age: 20
        },

        private: {
            createdAt: new Date().getTime(),
            phone: 123456
        }
    }

    var nomination = entries.push()
    nomination.setWithPriority(data, data.private.createdAt)

    pending.child(nomination.name()).set(true)    
}

// Retrieve current nomination status
var getStatus = function(id, callback) {
    approved.child(id).once('value', function(snapshot) {
        if (snapshot.val()) {
            callback(id, 'approved')
        } else {
            rejected.child(id).once('value', function(snapshot) {
                callback(id, snapshot.val() ? 'rejected' : 'pending')
            })
        }
    })
}

// Change status of nomination
var changeStatus = function(id, from, to) {
    status.child(from).child(id).remove()
    status.child(to).child(id).set(true)
}

Jedyną częścią implementacji, z którą się zmagam, jest obsługa zmian statusu, moje obecne podejście z pewnością może zostać ulepszone po:

_.each([pending, approved, rejected], function(status) {
    status.on('child_added', function(snapshot) {
        $('#' + snapshot.name()).removeClass('pending approved rejected').addClass(status.name())
    })
})

Planowałem używaćchild_changed nanominations/status ale nie byłem w stanie sprawić, by działało niezawodnie.

questionAnswers(3)

yourAnswerToTheQuestion