FirebaseExtended / firebase-queue

MIT License
786 stars 108 forks source link

Authorization rules in bolt #50

Open tirsen opened 8 years ago

tirsen commented 8 years ago

We're using the bolt compiler for our authorization rules. Can we get a port of the authorization rules to bolt please?

wconnorwalsh commented 8 years ago

+1

pandaiolo commented 8 years ago

Here is my attempt, seem to work. Customize to your own needs. Not sure about the ErrorDetail type, has it is not validated in the original format of the queue rules.

//
//
// Rules for the workers queue
//
//
path /queue/tasks {
    read() { auth.canProcessTasks }
    write() { auth.canAddTasks || auth.canProcessTasks }
    index() { ['_state'] }

    /{taskId} is Task {
        validate() {
            // Customize to your needs the following line
            this.hasChildren(['_property_1', ..., '_property_n']) || 
            (auth.canProcessTasks &&
                this.hasChildren(['_state', '_state_changed', '_progress']))
        }
    }
}

path /queue/specs {
    read() { auth.canAddSpecs || auth.canProcessTasks }
    write() { auth.canAddSpecs }

    /{specId} is Spec
}

type Task {
    _state: String | Null,
    _state_changed: InitialTimestamp | Null,
    _owner: String | Null,
    _progress: Percent | Null,
    _error_details: ErrorDetail | Null,
    _id: String | Null,
    _property_1: XXX, // Change with custom properties validation
    ...               // Change with custom properties validation
    _property_n: XXX, // Change with custom properties validation
}

type Spec {
    start_state: String | Null,
    in_progress_state: String,
    finished_state: String | Null,
    error_state: String | Null,
    timeout: PositiveNumber | Null,
}

type ErrorDetail {
    error: String | Null,
    error_stack: String | Null,
    previous_state: String | Null,
    original_task: Anything | Null,
    attempts: PositiveNumber | Null
}

type InitialTimestamp extends Number {
  validate() { noChange(this) || withInitialCondition(this, this == now) }
}

type PositiveNumber extends Number {
    validate() { this >= 0 }
}

type Percent extends Number {
    validate() { this <= 100 }
}

// Type `Any` has a bug, this is a workaround
// see https://github.com/firebase/bolt/issues/111
type Anything {
    validate() {
        this.isString() || this.isNumber() || this.isBoolean() || this.hasChildren()
    }
}

withInitialCondition(ref, exp) { isNew(ref) && exp }

isNew(ref) { prior(ref) == null }

noChange(ref) { ref == prior(ref) }
leblancmeneses commented 8 years ago

Thoughts on why firebase-queue should not exist in our bolt rules

    read() { auth.canAdministerQueue || auth.canProcessQueue }
    write() { auth.canAdministerQueue || auth.canProcessQueue }

What I am having problems with is the last list item. How can I make it atomic? Ideally, I would want firebase to support a trigger so as a collection is appended I could auto append the task queue. Until then, it seems we may need firebase-queue-watcherâ„¢ to watch a collection and append the queue task collection. Is there a project that already mirrors an existing collection, recovers on restarts where it left off?

mckoss commented 8 years ago

I fixed the Any bug in the Bolt repo yesterday if you want to try it out (I will release it via npm along with other bug fixes in the next day or so - probably as version 0.8.1).

BTW - while it currently works to call methods like hasChildren() and isBoolean() in your own validate methods, it's more idiomatic to use type statements.

// This Bolt definition ...
type Anything extends String | Number | Boolean | Object;
path /x is Anything;

// ... produces this JSON output:
{
  "rules": {
    "x": {
      ".validate": "newData.isString() || newData.isNumber() || newData.isBoolean() || newData.hasChildren()"
    }
  }
}
leblancmeneses commented 7 years ago

@mckoss Is there a way to get "$other": to be replaced with a custom expression?

"$other":{ '.validate': "auth != null && auth.uid == 'feature-worker'" }

benefits: 1) Forces the web client to match the Type specified on the path. 2) My Type doesn't care about firebase-queue internal data structures. 3) Allows my firebase queue worker to be able to write other queue specific properties when limiting write access with databaseAuthVariableOverride: { uid: "feature-worker" } to the rest of my database.