goldibex / targaryen

Test Firebase security rules without connecting to Firebase.
ISC License
242 stars 36 forks source link

Testing against .validate is not performed #45

Closed RomansBermans closed 7 years ago

RomansBermans commented 7 years ago

Hi all,

I am trying to run the following test:

...
   before(() => {
    ...
    targaryen.setFirebaseData({
      technicians: {
        'technician-admin': {
          created,
          profile,
          type: 'admin',
        }
      }
    });
  });
...
const admin = { uid: 'technician-admin', email: 'admin@echo.com' };
...
expect(admin).cannot.write({ index: 'firebase', query: '*' }).to.path('search/request/:id');
...

against the following rules:

{
  "rules": {
    "search": {
      "request": {
        "$request": {
          ".validate": "newData.hasChildren(['index', 'type', 'query'])",
          "index": {
            ".validate": "newData.isString() && newData.val().length > 0"
          },
          "type": {
            ".validate": "newData.isString() && newData.val().length > 0"
          },
          "query": {
            ".validate": "newData.isString() && newData.val().length > 0"
          },
          "$other": {
            ".validate": "false"
          },
          ".write": "data.val() == null && (auth != null && auth.uid != null) && (newData.child('type').val() == 'item' || newData.child('type').val() == 'practice' || root.child('technicians').child(auth.uid).child('type').val() == 'admin')"
        }
      }
    }
  }
}

but it fails with the following error:

1) database user:technician:admin /search /request /:id pass:
     AssertionError: Expected a user with credentials {"uid":"technician-admin","email":"admin@echo.com"} not to be able to write {"index":"firebase","query":"*"} to search/request/:id, but the rules allowed the write.
/search/request/:id:.write: "data.val() == null && (auth != null && auth.uid != null) && (newData.child('type').val() == 'item' || newData.child('type').val() == 'practice' || root.child('technicians').child(auth.uid).child('type').val() == 'admin')"
    => true
Write was allowed.
      at Assertion.<anonymous> (node_modules/targaryen/lib/chai.js:84:12)
      at Assertion.ctx.(anonymous function) [as path] (node_modules/chai/lib/chai/utils/addMethod.js:41:25)
      at Context.it (test/database/rules.targaryen.js:1234:76)

This test would not have failed if ".validate": "newData.hasChildren(['index', 'type', 'query'])" would have been evaluated, it seems that targaryen didn't pickup .validate

Any help would be appreciated. We were looking for a way to test Fireabase rules locally (we ran them against a Fireabase app until now) and a few days ago we have been recommended targaryen by Mike from the Firebase support team. We have rewritten 300 tests to run on targaryen but some things we are not able to test.

Thanks in advance, Romans

RomansBermans commented 7 years ago

In targaryen/lib/ruleset.js (line 338:340) I have changed:

    if (!state.newData.exists()) {
      skipValidate = true;
    }

to:

    if (path === currentPath && !state.newData.exists()) {
      skipValidate = true;
    }

And everything is fine now.

dinoboff commented 7 years ago

Can you try with master:

npm i targaryen@00c2c8ce7a2d90767b9a7b48eae70cc58454f0fd
dinoboff commented 7 years ago

@RomansBermans Can you try with with v2.3.0-0?

npm install targaryen@2.3.0-0
RomansBermans commented 7 years ago

I have tried v2.3.0-0 and v2.3.0-1 and I am getting now even more errors. We have got 400 tests that we run against Firebase database rules and they all pass without using targaryen and by running them against actual Firebase database (which is very slow). Below is one example that fails:

  1) database user:unauthenticated orders:
     AssertionError: Expected an unauthenticated user not to be able to read orders, but the rules allowed the read.
/:<no rules>
/orders/: "root.child('technicians').child(auth.uid).val() != null || auth.uid == 'server'"
    => true
Read was allowed.
      at Assertion.<anonymous> (node_modules/targaryen/lib/chai.js:72:16)
      at Assertion.ctx.(anonymous function) [as path] (node_modules/chai/lib/chai/utils/addMethod.js:41:25)
      at Context.it (test/database/rules.targaryen.js:15:48)

The rules for orders path are:

    "orders": {
      "$order": {
        ...
      },
      ".read": "root.child('technicians').child(auth.uid).val() != null || auth.uid == 'server'"
    },

On my tweaked version of Targaryen I got it working as expected, please have a look at the diff here https://github.com/goldibex/targaryen/compare/master...RomansBermans:master

mhuebert commented 7 years ago

@RomansBermans feedback from your testing setup is really valuable, thanks for sharing these results!

It looks like .child() is behaving inconsistently: the rules you've posted behave as expected if the expression root.child('technicians').child(auth.uid) is rewritten as root.child('technicians' + '/' + auth.uid). (I think these two forms should always be equivalent?)

Test: https://github.com/mhuebert/targaryen/blob/child-behavior/test/spec/lib/ruleset.js#L286

dinoboff commented 7 years ago

They should both be. I think bolt compile to the later form. I find the former more readable:

dinoboff commented 7 years ago

@RomansBermans @mhuebert

ps: you can try with npm install targaryen@goldibex/targaryen#next

Once 2.3 is released I will release a beta version of 3.0.0

RomansBermans commented 7 years ago

Thanks! I will give it a go in the next few days and let you know.

dinoboff commented 7 years ago

@RomansBermans npm targaryen@beta now point to the the upcoming 3.0.0 (I still to need to refine the public API before release).

RomansBermans commented 7 years ago

Thanks @dinoboff I have tried it and I am getting the following error:

1) database "before all" hook:                                                                                                                  
     Error: Proposed Firebase data is not valid: Invalid data node type: 1,2 (object)                                                             
      at Object.exports.setFirebaseData (node_modules/targaryen/lib/test-helpers.js:149:11)                                                       
      at Context.before (test/database/rules.targaryen.js:37:15) 

Firebase accepts does rules when we upload them.

RomansBermans commented 7 years ago

@dinoboff I just have tried with v3.0.0-beta.1 but getting this error:

  1) database user:unauthenticated orders:
     AssertionError: Expected an unauthenticated user not to be able to read orders, but the rules allowed the read.
/orders: read "root.child('technicians').child(auth.uid).val() != null || auth.uid == 'server'"
    => true
read was allowed.
      at Assertion.<anonymous> (node_modules/targaryen/plugins/chai.js:77:14)
      at Assertion.ctx.(anonymous function) [as path] (node_modules/chai/lib/chai/utils/addMethod.js:41:25)
      at Context.it (test/database/rules.targaryen.js:15:48)
dinoboff commented 7 years ago

I am guessing root.child('technicians').child(auth.uid).val() != null is the issue:

RomansBermans commented 7 years ago

@dinoboff the Realtime Database simulator works as expected:

screen shot 2016-11-15 at 09 38 52
dinoboff commented 7 years ago

87 should fix it

RomansBermans commented 7 years ago

Perfect, thanks!

RomansBermans commented 7 years ago

@dinoboff I just have tried with v2.3.2 and I am getting this:

3) database user:unauthenticated search/request/1479859609858:
     AssertionError: Expected an unauthenticated user not to be able to read search/request/1479859609858, but the rules allowed the read.
/:<no rules>
/search:<no rules>
/search/request/: "auth.uid == 'server'"
    => false
/search/request/1479859609858/: "auth.uid == data.child('creator').val()"
    => true
Read was allowed.
      at Assertion.<anonymous> (node_modules/targaryen/lib/chai.js:72:16)
      at Assertion.ctx.(anonymous function) [as path] (node_modules/chai/lib/chai/utils/addMethod.js:41:25)
      at Context.it (test/database/rules.targaryen.js:15:48)

My assumption here is that auth.uid is null as the user is unauthenticated and also data.child('creator').val() is null as there i no data at search/request/1479859609858

Again when using Firebase library this works as expected.

dinoboff commented 7 years ago

I am not sure how I can handle this one.

dinoboff commented 7 years ago

@RomansBermans

actually, I can't reproduce the issue in the simulator: auth.foo == root.child('foo/bar').val() will evaluate to true in the simulator if auth is set to null and if foo/bar doesn't not exist.

RomansBermans commented 7 years ago

@dinoboff really sorry you are right. I was passing incorrect auth object in the test that is using the firebase-admin module.

I will give 2.3.2 another go tomorrow.

dinoboff commented 7 years ago

No problem, keep posting any issue with the rule parser; I don't mind a few false positive.

RomansBermans commented 7 years ago

2.3.2 totally works for me:

screen shot 2016-11-23 at 01 59 03
RomansBermans commented 7 years ago

@dinoboff I have a question about what targaryen prints out when there is an error and was wondering if you could help out.

I have:

/* eslint-disable import/no-unresolved */

const { expect, targaryen } = require('./config');

const data = require('../data');

const rules = require('../../database/rules');

/* ************************************************************ */

const pass = (user, path, r = false, d = false, w = false) => {
  it(path, () => {
    expect(user)[`can${!r ? 'not' : ''}`].read.path(path);
    expect(user)[`can${!d ? 'not' : ''}`].write(null).to.path(path);
    if (typeof w === 'boolean') {
      expect(user)[`can${!w ? 'not' : ''}`].write().to.path(path);
    } else {
      Object.keys(w).forEach(k => {
        w[k].forEach(wk => {
          expect(user)[`can${k !== 'y' ? 'not' : ''}`].write(wk).to.path(path);
        });
      });
    }
  });
};

/* ************************************************************ */

describe('database', () => {
  const key = Date.now();

  before(() => {
    targaryen.setFirebaseData(data.initial);
    targaryen.setFirebaseRules(rules);
  });

  describe.only('user:authenticated', () => {
    const [uid, email] = ['UAUT1', 'uaut1@test.echo.co.uk'];

    pass({ uid, email }, `patients/${uid}`, true, true, {
      n: [
        data.ty.min.patient(email),
      ],
    });
  });

...

});

Which correctly fails with the following output:

Rs-MacBook-Pro:echo-data RomansBermans$ mocha test/database -R list --timeout 20000

  1) database user:authenticated patients/UAUT1

  0 passing (1s)
  1 failing

  1) database user:authenticated patients/UAUT1:
     AssertionError: Expected a user with credentials {"uid":"UAUT1","email":"uaut1@test.echo.co.uk"} not to be able to write {"_data":{"items":{"IT1":{"name":{".value":"Test Item"},"detail":{"icon":{".value":"tablet"},"category":{".value":"generic"},"type":{".value":"medicinal"},"charge":{".value":1}}},"IT2":{"name":{".value":"Test Item"},"detail":{"icon":{".value":"tablet"},"category":{".value":"generic"},"type":{".value":"medicinal"},"charge":{".value":1},"form":{".value":"tablet"},"pack":{"unit":{".value":"tablet"},"size":{".value":100}},"schedule":{".value":"1"},"coldchain":{".value":true},"discrete":{".value":true}},"description":{".value":"Test"},"warnings":{"0":{".value":"1"},"1":{".value":"2"}},"gtins":{"1":{".value":true},"2":{".value":true}},"keywords":{".value":"tablet generic medicinal"}}},"practices":{"PR1":{"name":{".value":"Test Practice"},"address":{"line1":{".value":"76 Oxford Street"},"city":{".value":"London"},"postcode":{".value":"W1D 1BS"},"country":{".value":"UK"}}},"PR2":{"name":{".value":"Test Practice"},"address":{"line1":{".value":"76 Oxford Street"},"city":{".value":"London"},"postcode":{".value":"W1D 1BS"},"country":{".value":"UK"},"line2":{".value":"Oxford House"},"coordinates":{"lat":{".value":51.5162782},"lng":{".value":-0.1340958}},"type":{".value":"commercial"}},"contacts":{"default":{".value":"1"},"list":{"1":{"value":{".value":"test@test.echo.co.uk"},"type":{".value":"email"}},"2":{"value":{".value":"+441234567890"},"type":{".value":"phone"}},"3":{"value":{".value":"+441234567890"},"type":{".value":"fax"}}},"main":{".value":"2"}},"eps":{".value":true}},"PR1P":{"name":{".value":"Test Practice"},"address":{"line1":{".value":"76 Oxford Street"},"city":{".value":"London"},"postcode":{".value":"W1D 1BS"},"country":{".value":"UK"},"line2":{".value":"Oxford House"},"coordinates":{"lat":{".value":51.5162782},"lng":{".value":-0.1340958}},"type":{".value":"commercial"}},"contacts":{"default":{".value":"1"},"list":{"1":{"value":{".value":"test@test.echo.co.uk"},"type":{".value":"email"}},"2":{"value":{".value":"+441234567890"},"type":{".value":"phone"}},"3":{"value":{".value":"+441234567890"},"type":{".value":"fax"}}},"main":{".value":"2"}},"eps":{".value":true},"parent":{".value":"PR1"}},"PR2P":{"name":{".value":"Test Practice"},"address":{"line1":{".value":"76 Oxford Street"},"city":{".value":"London"},"postcode":{".value":"W1D 1BS"},"country":{".value":"UK"},"line2":{".value":"Oxford House"},"coordinates":{"lat":{".value":51.5162782},"lng":{".value":-0.1340958}},"type":{".value":"commercial"}},"contacts":{"default":{".value":"1"},"list":{"1":{"value":{".value":"test@test.echo.co.uk"},"type":{".value":"email"}},"2":{"value":{".value":"+441234567890"},"type":{".value":"phone"}},"3":{"value":{".value":"+441234567890"},"type":{".value":"fax"}}},"main":{".value":"2"}},"eps":{".value":true},"parent":{".value":"PR2"}}},"pharmacies":{"PH1":{"created":{".value":1479911371892},"name":{".value":"Test Pharmacy"},"address":{"line1":{".value":"76 Oxford Street"},"city":{".value":"London"},"postcode":{".value":"W1D 1BS"},"country":{".value":"UK"}},"email":{".value":"test@test.echo.co.uk"},"phone":{".value":"+441234567890"},"logo":{".value":"https://firebasestorage.googleapis.com/v0/b/echo-data.appspot.com/o/pharmacies%2F-KTsaAryRpYlg7yyDryL%2Flogo%2F1475788261916.png?alt=media&token=2e2c983e-9e9b-4699-97bf-40cf70359e97"}},"PH2":{"created":{".value":1479911371892},"name":{".value":"Test Pharmacy"},"address":{"line1":{".value":"76 Oxford Street"},"city":{".value":"London"},"postcode":{".value":"W1D 1BS"},"country":{".value":"UK"},"line2":{".value":"Oxford House"},"coordinates":{"lat":{".value":51.5162782},"lng":{".value":-0.1340958}},"type":{".value":"commercial"}},"email":{".value":"test@test.echo.co.uk"},"phone":{".value":"+441234567890"},"logo":{".value":"https://firebasestorage.googleapis.com/v0/b/echo-data.appspot.com/o/pharmacies%2F-KTsaAryRpYlg7yyDryL%2Flogo%2F1475788261916.png?alt=media&token=2e2c983e-9e9b-4699-97bf-40cf70359e97"}}},"orders":{"OR1":{"created":{".value":1479911371892},"patient":{".value":"UPAT1"},"items":{"IT1":{"name":{".value":"Test Item"},"detail":{"icon":{".value":"tablet"},"category":{".value":"generic"},"type":{".value":"medicinal"},"charge":{".value":1}},"status":{"modified":{".value":1479911371892},"status":{".value":"new"}}},"IT2":{"name":{".value":"Test Item"},"detail":{"icon":{".value":"tablet"},"category":{".value":"generic"},"type":{".value":"medicinal"},"charge":{".value":1}},"status":{"modified":{".value":1479911371892},"status":{".value":"new"}}}},"delivery":{"type":{".value":"royalMail48"}},"status":{"modified":{".value":1479911371892},"status":{".value":"approved"}}},"OR2":{"created":{".value":1479911371892},"patient":{".value":"UPAT1"},"items":{"IT1":{"name":{".value":"Test Item"},"detail":{"icon":{".value":"tablet"},"category":{".value":"generic"},"type":{".value":"medicinal"},"charge":{".value":1},"form":{".value":"tablet"},"pack":{"unit":{".value":"tablet"},"size":{".value":100}},"schedule":{".value":"1"},"coldchain":{".value":true},"discrete":{".value":true}},"description":{".value":"Test"},"warnings":{"0":{".value":"1"},"1":{".value":"2"}},"gtins":{"1":{".value":true},"2":{".value":true}},"keywords":{".value":"tablet generic medicinal"},"status":{"modified":{".value":1479911371892},"status":{".value":"new"}},"reminder":{"id":{".value":"RE1"},"prescription":{".value":"take one tablet once a day"},"form":{".value":"tablet"},"supply":{"quantity":{".value":24},"packs":{".value":1},"start":{".value":1479945599999},"end":{".value":1479945600000}},"schedule":{"cycle":{".value":1},"weekly":{".value":true},"doses":{"0":{"day":{".value":1},"hours":{".value":8},"minutes":{".value":0},"quantity":{".value":1},"repeat":{".value":1}}}}},"archived":{".value":false}},"IT2":{"name":{".value":"Test Item"},"detail":{"icon":{".value":"tablet"},"category":{".value":"generic"},"type":{".value":"medicinal"},"charge":{".value":1},"form":{".value":"tablet"},"pack":{"unit":{".value":"tablet"},"size":{".value":100}},"schedule":{".value":"1"},"coldchain":{".value":true},"discrete":{".value":true}},"description":{".value":"Test"},"warnings":{"0":{".value":"1"},"1":{".value":"2"}},"gtins":{"1":{".value":true},"2":{".value":true}},"keywords":{".value":"tablet generic medicinal"},"status":{"modified":{".value":1479911371892},"status":{".value":"new"}},"reminder":{"id":{".value":"RE2"},"prescription":{".value":"take one tablet once a day"},"form":{".value":"tablet"},"supply":{"quantity":{".value":24},"packs":{".value":1},"start":{".value":1479945599999},"end":{".value":1479945600000}},"schedule":{"cycle":{".value":1},"weekly":{".value":true},"doses":{"0":{"day":{".value":1},"hours":{".value":8},"minutes":{".value":0},"quantity":{".value":1},"repeat":{".value":1}}}}},"archived":{".value":false}},"IT3":{"name":{".value":"Test Item"},"detail":{"icon":{".value":"tablet"},"category":{".value":"generic"},"type":{".value":"medicinal"},"charge":{".value":1},"form":{".value":"tablet"},"pack":{"unit":{".value":"tablet"},"size":{".value":100}},"schedule":{".value":"1"},"coldchain":{".value":true},"discrete":{".value":true}},"description":{".value":"Test"},"warnings":{"0":{".value":"1"},"1":{".value":"2"}},"gtins":{"1":{".value":true},"2":{".value":true}},"keywords":{".value":"tablet generic medicinal"},"status":{"modified":{".value":1479911371892},"status":{".value":"new"}},"reminder":{"id":{".value":"RE3"},"prescription":{".value":"take one tablet once a day"},"form":{".value":"tablet"},"supply":{"quantity":{".value":24},"packs":{".value":1},"start":{".value":1479945599999},"end":{".value":1479945600000}},"schedule":{"cycle":{".value":1},"weekly":{".value":true},"doses":{"0":{"day":{".value":1},"hours":{".value":8},"minutes":{".value":0},"quantity":{".value":1},"repeat":{".value":1}}}}},"archived":{".value":false}}},"delivery":{"type":{".value":"royalMail48"},"id":{".value":"ESSH1"},"batch":{".value":"BA1"},"package":{".value":"LargeLetter"},"weight":{".value":10},"tracking":{"status":{"modified":{".value":1479911371892},"status":{".value":"pre_transit"}}},"status":{"modified":{".value":1479911371892},"status":{".value":"purchased"}}},"status":{"modified":{".value":1479911371892},"status":{".value":"approved"}},"payment":{"id":{".value":"STCH1"},"total":{".value":840},"status":{"modified":{".value":1479911371892},"status":{".value":"captured"}}},"fax":{"id":{".value":"HFTR1"},"to":{".value":"+441234567890"},"status":{"modified":{".value":1479911371892},"status":{".value":"P"}}},"pinned":{".value":true}},"OR3":{"created":{".value":1479911371892},"patient":{".value":"UPAT2"},"items":{"IT1":{"name":{".value":"Test Item"},"detail":{"icon":{".value":"tablet"},"category":{".value":"generic"},"type":{".value":"medicinal"},"charge":{".value":1}},"status":{"modified":{".value":1479911371892},"status":{".value":"new"}}},"IT2":{"name":{".value":"Test Item"},"detail":{"icon":{".value":"tablet"},"category":{".value":"generic"},"type":{".value":"medicinal"},"charge":{".value":1}},"status":{"modified":{".value":1479911371892},"status":{".value":"new"}}},"IT3":{"name":{".value":"Test Item"},"detail":{"icon":{".value":"tablet"},"category":{".value":"generic"},"type":{".value":"medicinal"},"charge":{".value":1}},"status":{"modified":{".value":1479911371892},"status":{".value":"new"}}}},"delivery":{"type":{".value":"royalMail48"}},"status":{"modified":{".value":1479911371892},"status":{".value":"approved"}}},"OR4":{"created":{".value":1479911371892},"patient":{".value":"UPAT1"},"items":{"IT1":{"name":{".value":"Test Item"},"detail":{"icon":{".value":"tablet"},"category":{".value":"generic"},"type":{".value":"medicinal"},"charge":{".value":1}},"status":{"modified":{".value":1479911371892},"status":{".value":"new"}}},"IT2":{"name":{".value":"Test Item"},"detail":{"icon":{".value":"tablet"},"category":{".value":"generic"},"type":{".value":"medicinal"},"charge":{".value":1}},"status":{"modified":{".value":1479911371892},"status":{".value":"new"}}}},"delivery":{"type":{".value":"royalMail48"},"status":{"modified":{".value":1479513600000},"status":{".value":"purchased"}}},"status":{"modified":{".value":1479911371892},"status":{".value":"dispatched"}}},"OR5":{"created":{".value":1479911371892},"patient":{".value":"UPAT1"},"items":{"IT1":{"name":{".value":"Test Item"},"detail":{"icon":{".value":"tablet"},"category":{".value":"generic"},"type":{".value":"medicinal"},"charge":{".value":1}},"status":{"modified":{".value":1479911371892},"status":{".value":"new"}}},"IT2":{"name":{".value":"Test Item"},"detail":{"icon":{".value":"tablet"},"category":{".value":"generic"},"type":{".value":"medicinal"},"charge":{".value":1}},"status":{"modified":{".value":1479911371892},"status":{".value":"new"}}}},"delivery":{"type":{".value":"royalMail48"},"status":{"modified":{".value":1479513600000},"status":{".value":"purchased"}}},"status":{"modified":{".value":1479911371892},"status":{".value":"paid"}}}},"patients":{"UPAT1":{"created":{".value":1479911371892},"profile":{"firstName":{".value":"Test"},"lastName":{".value":"Patient"},"email":{".value":"upat1@test.echo.co.uk"}},"status":{"modified":{".value":1479911371892},"status":{".value":"new"}}},"UPAT2":{"created":{".value":1479911371892},"profile":{"firstName":{".value":"Test"},"lastName":{".value":"Patient"},"email":{".value":"upat2@test.echo.co.uk"},"phone":{".value":"+441234567890"},"addresses":{"default":{".value":"2"},"list":{"1":{"line1":{".value":"100 Knightsbridge"},"city":{".value":"London"},"postcode":{".value":"SW1X 7LJ"},"country":{".value":"UK"},"line2":{".value":"One Hyde Park"},"coordinates":{"lat":{".value":51.502024},"lng":{".value":-0.1645669}},"type":{".value":"residential"}},"2":{"line1":{".value":"76 Oxford Street"},"city":{".value":"London"},"postcode":{".value":"W1D 1BS"},"country":{".value":"UK"},"line2":{".value":"Oxford House"},"coordinates":{"lat":{".value":51.5162782},"lng":{".value":-0.1340958}},"type":{".value":"commercial"}}},"main":{".value":"1"}},"birthday":{".value":-2177452800000},"nhsNumber":{".value":"1234567890"},"gender":{".value":"male"},"title":{".value":"mr"},"emergencyPhone":{".value":"+441234567890"}},"status":{"modified":{".value":1479911371892},"status":{".value":"new"}},"practice":{".value":"PR1"},"pharmacy":{"id":{".value":"PH1"},"nomination":{"created":{".value":1479911371892},"signature":{".value":"https://firebasestorage.googleapis.com/v0/b/echo-data.appspot.com/o/pharmacies%2F-KTsaAryRpYlg7yyDryL%2Flogo%2F1475788261916.png?alt=media&token=2e2c983e-9e9b-4699-97bf-40cf70359e97"},"status":{"modified":{".value":1479911371892},"status":{".value":"nominated"}}}},"exemptions":{"b":{"created":{".value":1479911371892},"evidence":{".value":"patients/1234567890/exemptions/b/evidence/1479388742415@2x.png"},"expiry":{".value":1479945599999},"status":{"modified":{".value":1479911371892},"status":{".value":"exemptEvidenceNotSeen"}}},"d":{"created":{".value":1479911371892},"evidence":{".value":"patients/1234567890/exemptions/b/evidence/1479388742415@2x.png"},"expiry":{".value":1479945599999},"status":{"modified":{".value":1479911371892},"status":{".value":"new"}}}},"stripe":{"id":{".value":"STCU1"},"cards":{"default":{".value":"1"},"list":{"1":{"brand":{".value":"Visa"},"last4":{".value":"4242"},"month":{".value":1},"year":{".value":2021},"name":{".value":"Test"}},"2":{"brand":{".value":"Visa"},"last4":{".value":"4242"},"month":{".value":1},"year":{".value":2021},"name":{".value":"Test"}}},"main":{".value":"2"}}},"settings":{"notifications":{"push":{"enabled":{".value":true},"tokens":{"1":{".value":true},"2":{".value":true}}},"sms":{"enabled":{".value":true}}}}},"UAUT1":{"created":{".value":1479911372034},"profile":{"firstName":{".value":"Test"},"lastName":{".value":"Patient"},"email":{".value":"uaut1@test.echo.co.uk"}},"status":{"modified":{".value":1479911372034},"status":{".value":"new"}}}},"technicians":{"UTEC1":{"created":{".value":1479911371892},"profile":{"firstName":{".value":"Test"},"lastName":{".value":"Test"},"email":{".value":"utec1@echo.co.uk"}}},"UTEC2":{"created":{".value":1479911371892},"profile":{"firstName":{".value":"Test"},"lastName":{".value":"Test"},"email":{".value":"utec1@echo.co.uk"},"phone":{".value":"+441234567890"}}}},"constants":{"address":{"type":{"residential":{".value":"Residential"},"commercial":{".value":"Commercial"}}},"contact":{"type":{"email":{".value":"Email"},"fax":{".value":"Fax"},"phone":{".value":"Phone"}}},"notification":{"type":{"patient":{"nomination":{"new":{"title":{".value":"New"},"body":{".value":"Our pharmacy team is now going to set up your account. You'll receive a confirmation email shortly."},"send":{"message":{".value":true},"push":{".value":true}}},"nominated":{"title":{".value":"Welcome to Echo"},"body":{".value":"Your registration has been successful! Our partner pharmacy can now process prescriptions from your GP."},"send":{"message":{".value":true},"push":{".value":true},"email":{".value":"patient-nomination"}}},"unnominated":{".value":false},"notFound":{"title":{".value":"Echo can't find you"},"body":{".value":"We are having trouble finding your NHS details. Please check your email for a message from one of our pharmacy team with more information."},"send":{"message":{".value":true},"push":{".value":true},"email":{".value":"patient-nomination"}}}}},"order":{"new":{"title":{".value":"Order requested"},"body":{".value":"We're now going to contact your GP and arrange your repeat prescription. This can take up to two working days. We'll be in touch as soon as we hear back from the surgery."},"send":{"message":{".value":true},"push":{".value":true}}},"approvalRequested":{"title":{".value":"Approval requested"},"body":{".value":"Your GP is now reviewing your order. Please allow three working days for approval. We’ll contact you as soon as we hear back."},"send":{"message":{".value":true},"push":{".value":true}}},"needsReview":{"title":{".value":"Order needs review"},"body":{".value":"Order on hold - your GP has asked for more information, please check your email for further details."},"send":{"message":{".value":true},"push":{".value":true},"email":{".value":"patient-order"}}},"approved":{"title":{".value":"Order approved"},"body":{".value":"Good news — we’ve received your prescription. Please open Echo and press ‘dispatch treatment’ to complete your order."},"send":{"message":{".value":true},"push":{".value":true},"email":{".value":"patient-order"},"sms":{".value":true}}},"dispatched":{"title":{".value":"Order dispatched"},"body":{".value":"Your order has been dispatched."},"send":{"message":{".value":true},"push":{".value":true},"email":{".value":"patient-order"}}},"cancelled":{"title":{".value":"Order cancelled"},"body":{".value":"Your order has been cancelled. If you believe you have received this in error please get in touch."},"send":{"message":{".value":true},"push":{".value":true}}}},"reminder":{"5":{"title":{".value":"Reminder"},"body":{".value":"You are about to run out of ${reminder.name}. Please reorder and we will contact your GP ASAP."},"send":{"message":{".value":true},"push":{".value":true},"email":{".value":"patient-reminder"},"sms":{".value":true}}},"10":{"title":{".value":"Its time to reorder!"},"body":{".value":"It looks like you’ve got about ten days of ${reminder.name} left. Please open Echo and reorder."},"send":{"message":{".value":true},"push":{".value":true}}}}}},"item":{"icon":{"default":{".value":"@2x.png"},"tablet":{".value":"@2x.png"},"capsule":{".value":"@2x.png"},"bottle":{".value":"@2x.png"},"drop":{".value":"@2x.png"},"dressing":{".value":"@2x.png"},"tubeCylinder":{".value":"@2x.png"},"needle":{".value":"@2x.png"},"syringe":{".value":"@2x.png"},"sachet":{".value":"@2x.png"},"stocking":{".value":"@2x.png"},"patch":{".value":"@2x.png"},"inhaler":{".value":"@2x.png"},"tub":{".value":"@2x.png"},"testStrip":{".value":"@2x.png"},"spray":{".value":"@2x.png"}},"category":{"branded":{".value":"Branded"},"generic":{".value":"Generic"}},"type":{"medicinal":{".value":"Medicinal"},"other":{".value":"Other"}},"charge":{".value":840},"warning":{"1":{".value":"Warning: This medicine may make you sleepy."},"2":{".value":"Warning: This medicine may make you sleepy. If this happens, do not drive or use tools or machines. Do not drink alcohol."},"3":{".value":"Warning: This medicine may make you sleepy. If this happens, do not drive or use tools or machines."},"4":{".value":"Warning: Do not drink alcohol."},"5":{".value":"Do not take indigestion remedies 2 hours before or after you take this medicine."},"6":{".value":"Do not take indigestion remedies, or medicines containing iron or zinc, 2 hours before or after you take this medicine."},"7":{".value":"Do not take milk, indigestion remedies, or medicines containing iron or zinc, 2 hours before or after you take this medicine."},"8":{".value":"Warning: Do not stop taking this medicine unless your doctor tells you to stop."},"9":{".value":"Space the doses evenly throughout the day. Keep taking this medicine until the course is finished, unless you are told to stop."},"10":{".value":"Warning: Read the additional information given with this medicine."},"11":{".value":"Protect your skin from sunlight—even on a bright but cloudy day. Do not use sunbeds."},"12":{".value":"Do not take anything containing aspirin while taking this medicine."},"13":{".value":"Dissolve or mix with water before taking."},"14":{".value":"This medicine may colour your urine. This is harmless."},"15":{".value":"Caution: flammable. Keep your body away from fire or flames after you have put on the medicine."},"16":{".value":"Dissolve the tablet under your tongue—do not swallow. Store the tablets in this bottle with the cap tightly closed. Get a new supply 8 weeks after opening."},"17":{".value":"Do not take more than the advised quantity in 24 hours."},"18":{".value":"Do not take more than the advised quantity in 24 hours. Also, take care not to exceed the total weekly dose."},"19":{".value":"Warning: This medicine makes you sleepy. If you still feel sleepy the next day, do not drive or use tools or machines. Do not drink alcohol."},"20":{".value":"(No warning used) ."},"21":{".value":"Take with or just after food, or a meal."},"22":{".value":"Take 30 to 60 minutes before food."},"23":{".value":"Take this medicine when your stomach is empty. This means an hour before food or 2 hours after food."},"24":{".value":"Suck or chew this medicine."},"25":{".value":"Swallow this medicine whole. Do not chew or crush."},"26":{".value":"Dissolve this medicine under your tongue."},"27":{".value":"Take with a full glass of water."},"28":{".value":"Spread thinly on the affected skin only."},"29":{".value":"Do not take more than 2 at any one time. Do not take more than 8 in 24 hours."},"30":{".value":"Contains paracetamol. Do not take anything else containing paracetamol while taking this medicine. Talk to a doctor at once if you take too much of this medicine, even if you feel well."},"31":{".value":"(No warning used)."},"32":{".value":"Contains aspirin. Do not take anything else containing aspirin while taking this medicine."}}},"order":{"item":{"status":{"new":{".value":"New"},"approved":{".value":"Approved"},"needsReview":{".value":"Needs Review"},"cancelled":{".value":"Cancelled"}}},"delivery":{"type":{"royalMail48":{"name":{".value":"Free - Royal Mail 48®"},"charge":{".value":0},"signature":{".value":false},"time":{".value":172800000},"restrictedSchedules":{"0":{".value":"2"},"1":{".value":"3"},"2":{".value":"4"},"3":{".value":"5"},"4":{".value":"6"},"5":{".value":"7"},"6":{".value":"8"},"7":{".value":"9"},"8":{".value":"10"}},"active":{".value":true}},"royalMail24SignedFor":{"name":{".value":"Royal Mail 24 Signed For®"},"charge":{".value":495},"signature":{".value":true},"time":{".value":86400000},"restrictedSchedules":{"0":{".value":"2"},"1":{".value":"4"},"2":{".value":"7"}},"active":{".value":true}},"royalMailTracked48":{".value":true},"royalMailTracked24":{".value":true},"royalMailTracked48SignedFor":{".value":true},"royalMailTracked24SignedFor":{".value":true},"collectPharmacySW1W0LJ":{".value":true}},"package":{"LargeLetter":{"label":{".value":"LargeLetter"},"weight":{"max":{".value":26.4}}},"SmallParcel":{"label":{".value":"SmallParcel"},"weight":{"max":{".value":70.5}}},"MediumParcel":{"label":{".value":"MediumParcel"},"weight":{"max":{".value":705.4}}}},"status":{"purchased":{".value":"Purchased"},"refunded":{".value":"Refunded"}}},"payment":{"status":{"captured":{".value":"Captured"},"refunded":{".value":"Refunded"}}},"fax":{"status":{"T":{".value":"Transmitting"},"P":{".value":"Pending"},"S":{".value":"Sent"},"E":{".value":"Error"},"H":{".value":"On Hold"},"B":{".value":"Line Busy"},"N":{".value":"No Answer"},"A":{".value":"Number Unallocated"},"D":{".value":"Line Disonnected"},"L":{".value":"Number Blacklisted"},"U":{".value":"Unknown Error"}}},"status":{"new":{".value":"New"},"approvalRequested":{".value":"Approval Requested"},"needsReview":{".value":"Needs Review"},"approved":{".value":"Approved"},"paid":{".value":"Paid"},"dispatched":{".value":"Dispatched"},"delivered":{".value":"Delivered"},"merged":{".value":"Merged"},"cancelled":{".value":"Cancelled"}}},"patient":{"gender":{"male":{".value":"Male"},"female":{".value":"Female"}},"title":{"mr":{".value":"Mr"},"mrs":{".value":"Mrs"},"miss":{".value":"Miss"},"dr":{".value":"Dr"},"prof":{".value":"Prof"}},"nomination":{"status":{"new":{".value":"New"},"nominated":{".value":"Nominated"},"unnominated":{".value":"Unnominated"},"notFound":{".value":"Not Found"}}},"exemption":{"type":{"b":{".value":"I am 18 years of age and in full-time education"},"c":{".value":"I am 60 years of age or over"},"d":{".value":"I have a valid maternity exemption certificate"},"e":{".value":"I have a valid medical exemption certificate"},"f":{".value":"I have a valid prescription pre-payment certificate"},"g":{".value":"I have a valid War Pension exemption certificate"},"h":{".value":"I, or my partner, get(s) Income Support or income-related Employment and Support Allowance"},"k":{".value":"I, or my partner get(s) income-based Jobseeker's Allowance"},"l":{".value":"I am named on a current HC2 charges certificate"},"m":{".value":"I am entitled to, or named on, a valid NHS Tax Credit Exemption Certificate"},"s":{".value":"I have a partner who gets Pension Credit guarantee credit (PCGC)"},"x":{".value":"I was prescribed free-of charge contraceptives"},"bt":{".value":"My GP and registered home address are based in Northern Ireland"}},"status":{"new":{".value":"New"},"exemptEvidenceSeen":{".value":"Exempt (Evidence Seen)"},"exemptEvidenceNotSeen":{".value":"Exempt (Evidence Not Seen)"},"invalid":{".value":"Invalid"},"exemptContraception":{".value":true}}},"status":{"new":{".value":"New"},"active":{".value":"Active"},"suspended":{".value":"Suspended"}}},"search":{"geo":{"distance":{".value":"10km"}},"paths":{"0":{"index":{".value":"items"},"path":{".value":"items"},"toArray":{"gtins":{".value":true}},"type":{".value":"item"}},"1":{"index":{".value":"practices"},"path":{".value":"practices"},"toArray":{"contacts":{"list":{".value":true}}},"type":{".value":"practice"}},"2":{"index":{".value":"orders"},"path":{".value":"orders"},"toArray":{"items":{".value":true}},"type":{".value":"order"}},"3":{"index":{".value":"patients"},"path":{".value":"patients"},"toArray":{"exemptions":{".value":true}},"type":{".value":"patient"}}}},"asset":{"logo":{"eps":{".value":"https://firebasestorage.googleapis.com/v0/b/echo-data.appspot.com/o/assets%2Feps-logo.jpg?alt=media&token=f0874957-133e-4749-8519-ef7fe94ac162"}}},"CO1":{".value":true},"CO2":{".value":true}},"queue":{"specs":{"notification":{"start_state":{".value":"notification"},"in_progress_state":{".value":"notification_in_progress"},"error_state":{".value":"notification_error"},"timeout":{".value":300000},"retries":{".value":0}},"SP1":{"in_progress_state":{".value":"test_spec_in_progress"}},"SP2":{"in_progress_state":{".value":"test_spec_in_progress"},"start_state":{".value":"test_spec"},"finished_state":{".value":"test_spec_finished"},"error_state":{".value":"test_spec_error"},"timeout":{".value":1000},"retries":{".value":0}}},"tasks":{"TA1":{"_state":{".value":"test_spec"},"creator":{".value":"UPAT1"}},"TA2":{"_state":{".value":"test_spec"},"creator":{".value":"UTEC1"}}}},"search":{"request":{"RE1":{"creator":{".value":"UPAT1"},"index":{".value":"items"},"type":{".value":"item"},"query":{"query":{"1":{".value":true}},"sort":{"1":{".value":true}},"from":{".value":1},"size":{".value":1}}},"RE2":{"creator":{".value":"UTEC1"},"index":{".value":"items"},"type":{".value":"item"},"query":{"query":{"1":{".value":true}},"sort":{"1":{".value":true}},"from":{".value":1},"size":{".value":1}}}},"response":{"RE1":{"hits":{"0":{"_id":{".value":"1"}}},"max_score":{".value":0.30685282},"total":{".value":1}},"RE2":{"error":{"1":{".value":true}}}}},"notes":{"UPAT1":{"NO1":{"created":{".value":1479911371892},"modified":{".value":1479911371892},"creator":{".value":"UTEC1"},"text":{".value":"Test"}},"NO2":{"created":{".value":1479911371892},"modified":{".value":1479911371892},"creator":{".value":"UTEC1"},"text":{".value":"Test"},"pinned":{".value":true}}}},"messages":{"UPAT1":{"ME1":{"created":{".value":1479911371892},"title":{".value":"Title"},"type":{".value":"order/new"}},"ME2":{"created":{".value":1479911371892},"title":{".value":"Title"},"type":{".value":"order/new"},"body":{".value":"Body"}}}},"batches":{"BA1":{"id":{".value":"ESBA1"},"created":{".value":1479911371892},"size":{".value":1},"status":{"modified":{".value":1479911371892},"status":{".value":"creating"}}},"BA2":{"id":{".value":"ESBA2"},"created":{".value":1479911371892},"size":{".value":1},"status":{"modified":{".value":1479911371892},"status":{".value":"creating"}},"form":{"url":{".value":"https://firebasestorage.googleapis.com/v0/b/echo-data.appspot.com/o/pharmacies%2F-KTsaAryRpYlg7yyDryL%2Flogo%2F1475788261916.png?alt=media&token=2e2c983e-9e9b-4699-97bf-40cf70359e97"},"status":{"modified":{".value":1479911371892},"status":{".value":"creating"}}}}},"reminders":{"RE1":{"patient":{".value":"UPAT1"},"name":{".value":"Test Item"},"end":{".value":1480377599999}},"RE2":{"patient":{".value":"UPAT1"},"name":{".value":"Test Item"},"end":{".value":1480809599999}},"RE3":{"patient":{".value":"UPAT2"},"name":{".value":"Test Item"},"end":{".value":1480377599999}},"RE4":{"patient":{".value":"UPAT2"},"name":{".value":"Test Item"},"end":{".value":1480809599999}}},"patients-orders":{"UPAT1":{"OR1":{"created":{".value":1479911371892},"patient":{".value":"UPAT1"},"items":{"IT1":{"name":{".value":"Test Item"},"detail":{"icon":{".value":"tablet"},"category":{".value":"generic"},"type":{".value":"medicinal"},"charge":{".value":1}},"status":{"modified":{".value":1479911371892},"status":{".value":"new"}}},"IT2":{"name":{".value":"Test Item"},"detail":{"icon":{".value":"tablet"},"category":{".value":"generic"},"type":{".value":"medicinal"},"charge":{".value":1}},"status":{"modified":{".value":1479911371892},"status":{".value":"new"}}}},"delivery":{"type":{".value":"royalMail48"}},"status":{"modified":{".value":1479911371892},"status":{".value":"approved"}}},"OR2":{"created":{".value":1479911371892},"patient":{".value":"UPAT1"},"items":{"IT1":{"name":{".value":"Test Item"},"detail":{"icon":{".value":"tablet"},"category":{".value":"generic"},"type":{".value":"medicinal"},"charge":{".value":1},"form":{".value":"tablet"},"pack":{"unit":{".value":"tablet"},"size":{".value":100}},"schedule":{".value":"1"},"coldchain":{".value":true},"discrete":{".value":true}},"description":{".value":"Test"},"warnings":{"0":{".value":"1"},"1":{".value":"2"}},"gtins":{"1":{".value":true},"2":{".value":true}},"keywords":{".value":"tablet generic medicinal"},"status":{"modified":{".value":1479911371892},"status":{".value":"new"}},"reminder":{"id":{".value":"RE1"},"prescription":{".value":"take one tablet once a day"},"form":{".value":"tablet"},"supply":{"quantity":{".value":24},"packs":{".value":1},"start":{".value":1479945599999},"end":{".value":1479945600000}},"schedule":{"cycle":{".value":1},"weekly":{".value":true},"doses":{"0":{"day":{".value":1},"hours":{".value":8},"minutes":{".value":0},"quantity":{".value":1},"repeat":{".value":1}}}}},"archived":{".value":false}},"IT2":{"name":{".value":"Test Item"},"detail":{"icon":{".value":"tablet"},"category":{".value":"generic"},"type":{".value":"medicinal"},"charge":{".value":1},"form":{".value":"tablet"},"pack":{"unit":{".value":"tablet"},"size":{".value":100}},"schedule":{".value":"1"},"coldchain":{".value":true},"discrete":{".value":true}},"description":{".value":"Test"},"warnings":{"0":{".value":"1"},"1":{".value":"2"}},"gtins":{"1":{".value":true},"2":{".value":true}},"keywords":{".value":"tablet generic medicinal"},"status":{"modified":{".value":1479911371892},"status":{".value":"new"}},"reminder":{"id":{".value":"RE2"},"prescription":{".value":"take one tablet once a day"},"form":{".value":"tablet"},"supply":{"quantity":{".value":24},"packs":{".value":1},"start":{".value":1479945599999},"end":{".value":1479945600000}},"schedule":{"cycle":{".value":1},"weekly":{".value":true},"doses":{"0":{"day":{".value":1},"hours":{".value":8},"minutes":{".value":0},"quantity":{".value":1},"repeat":{".value":1}}}}},"archived":{".value":false}},"IT3":{"name":{".value":"Test Item"},"detail":{"icon":{".value":"tablet"},"category":{".value":"generic"},"type":{".value":"medicinal"},"charge":{".value":1},"form":{".value":"tablet"},"pack":{"unit":{".value":"tablet"},"size":{".value":100}},"schedule":{".value":"1"},"coldchain":{".value":true},"discrete":{".value":true}},"description":{".value":"Test"},"warnings":{"0":{".value":"1"},"1":{".value":"2"}},"gtins":{"1":{".value":true},"2":{".value":true}},"keywords":{".value":"tablet generic medicinal"},"status":{"modified":{".value":1479911371892},"status":{".value":"new"}},"reminder":{"id":{".value":"RE3"},"prescription":{".value":"take one tablet once a day"},"form":{".value":"tablet"},"supply":{"quantity":{".value":24},"packs":{".value":1},"start":{".value":1479945599999},"end":{".value":1479945600000}},"schedule":{"cycle":{".value":1},"weekly":{".value":true},"doses":{"0":{"day":{".value":1},"hours":{".value":8},"minutes":{".value":0},"quantity":{".value":1},"repeat":{".value":1}}}}},"archived":{".value":false}}},"delivery":{"type":{".value":"royalMail48"},"id":{".value":"ESSH1"},"batch":{".value":"BA1"},"package":{".value":"LargeLetter"},"weight":{".value":10},"tracking":{"status":{"modified":{".value":1479911371892},"status":{".value":"pre_transit"}}},"status":{"modified":{".value":1479911371892},"status":{".value":"purchased"}}},"status":{"modified":{".value":1479911371892},"status":{".value":"approved"}},"payment":{"id":{".value":"STCH1"},"total":{".value":840},"status":{"modified":{".value":1479911371892},"status":{".value":"captured"}}},"fax":{"id":{".value":"HFTR1"},"to":{".value":"+441234567890"},"status":{"modified":{".value":1479911371892},"status":{".value":"P"}}},"pinned":{".value":true}},"OR4":{"created":{".value":1479911371892},"patient":{".value":"UPAT1"},"items":{"IT1":{"name":{".value":"Test Item"},"detail":{"icon":{".value":"tablet"},"category":{".value":"generic"},"type":{".value":"medicinal"},"charge":{".value":1}},"status":{"modified":{".value":1479911371892},"status":{".value":"new"}}},"IT2":{"name":{".value":"Test Item"},"detail":{"icon":{".value":"tablet"},"category":{".value":"generic"},"type":{".value":"medicinal"},"charge":{".value":1}},"status":{"modified":{".value":1479911371892},"status":{".value":"new"}}}},"delivery":{"type":{".value":"royalMail48"},"status":{"modified":{".value":1479513600000},"status":{".value":"purchased"}}},"status":{"modified":{".value":1479911371892},"status":{".value":"dispatched"}}},"OR5":{"created":{".value":1479911371892},"patient":{".value":"UPAT1"},"items":{"IT1":{"name":{".value":"Test Item"},"detail":{"icon":{".value":"tablet"},"category":{".value":"generic"},"type":{".value":"medicinal"},"charge":{".value":1}},"status":{"modified":{".value":1479911371892},"status":{".value":"new"}}},"IT2":{"name":{".value":"Test Item"},"detail":{"icon":{".value":"tablet"},"category":{".value":"generic"},"type":{".value":"medicinal"},"charge":{".value":1}},"status":{"modified":{".value":1479911371892},"status":{".value":"new"}}}},"delivery":{"type":{".value":"royalMail48"},"status":{"modified":{".value":1479513600000},"status":{".value":"purchased"}}},"status":{"modified":{".value":1479911371892},"status":{".value":"paid"}}}},"UPAT2":{"OR3":{"created":{".value":1479911371892},"patient":{".value":"UPAT2"},"items":{"IT1":{"name":{".value":"Test Item"},"detail":{"icon":{".value":"tablet"},"category":{".value":"generic"},"type":{".value":"medicinal"},"charge":{".value":1}},"status":{"modified":{".value":1479911371892},"status":{".value":"new"}}},"IT2":{"name":{".value":"Test Item"},"detail":{"icon":{".value":"tablet"},"category":{".value":"generic"},"type":{".value":"medicinal"},"charge":{".value":1}},"status":{"modified":{".value":1479911371892},"status":{".value":"new"}}},"IT3":{"name":{".value":"Test Item"},"detail":{"icon":{".value":"tablet"},"category":{".value":"generic"},"type":{".value":"medicinal"},"charge":{".value":1}},"status":{"modified":{".value":1479911371892},"status":{".value":"new"}}}},"delivery":{"type":{".value":"royalMail48"}},"status":{"modified":{".value":1479911371892},"status":{".value":"approved"}}}}}},"_timestamp":1479911372034,"_path":"patients/UAUT1"} to patients/UAUT1, but the rules allowed the write.
/patients/UAUT1:.write: "data.val() == null && (auth.uid != null && auth.uid == $patient) && !(newData.parent().parent().child('technicians').child($patient).val() != null)"
    => true
/patients/UAUT1:.validate: "newData.hasChildren(['created', 'profile', 'status'])"
    => true
/patients/UAUT1/created:.validate: "newData.isNumber() && (data.val() == null ? newData.val() <= now && newData.val() >= now - 6666 : data.val() == newData.val())"
    => true
/patients/UAUT1/profile:.validate: "newData.hasChildren(['firstName', 'lastName', 'email'])"
    => true
/patients/UAUT1/profile/firstName:.validate: "newData.isString() && newData.val().length > 0"
    => true
/patients/UAUT1/profile/lastName:.validate: "newData.isString() && newData.val().length > 0"
    => true
/patients/UAUT1/profile/email:.validate: "newData.isString() && newData.val().length > 0 && newData.val().matches(/^[A-z0-9._%+-]+@[A-z0-9.-]+\.[A-z]{2,}$/) && (auth.email == newData.val() || data.val() == newData.val())"
    => true
/patients/UAUT1/status:.validate: "newData.hasChildren(['status']) && (auth.uid != null && auth.uid == $patient ? newData.child('status').val() == 'new' : true)"
    => true
/patients/UAUT1/status/modified:.validate: "newData.isNumber() && (newData.val() <= now && newData.val() >= now - 6666)"
    => true
/patients/UAUT1/status/status:.validate: "newData.isString() && newData.val().length > 0 && newData.parent().parent().parent().parent().child('constants').child('patient/status/' + newData.val()).val() != null"
    => true

      at Assertion.<anonymous> (node_modules/targaryen/lib/chai.js:99:12)
      at Assertion.ctx.(anonymous function) [as path] (node_modules/chai/lib/chai/utils/addMethod.js:41:25)
      at w.(anonymous function).forEach.wk (test/database/rules.targaryen.js:22:69)
      at Array.forEach (native)
      at Object.keys.forEach.k (test/database/rules.targaryen.js:21:14)
      at Array.forEach (native)
      at Context.it (test/database/rules.targaryen.js:20:22)

Why does targaryen print the whole test data set that was set via targaryen.setFirebaseData(data.initial):

Expected a user with credentials {"uid":"UAUT1","email":"uaut1@test.echo.co.uk"} not to be able to write {"_data":"{"items":{"IT1": ...} to patients/UAUT1, but the rules allowed the write.

If (I would assume) in the case that I am testing it should be printing: Expected a user with credentials {"uid":"UAUT1","email":"uaut1@test.echo.co.uk"} not to be able to write { created: { '.sv': 'timestamp' }, profile: { firstName: 'Test', lastName: 'Patient', email: 'uaut1@test.echo.co.uk' }, status: { modified: { '.sv': 'timestamp' }, status: 'new' } } to patients/UAUT1, but the rules allowed the write.?

Any ideas?

dinoboff commented 7 years ago

There's a bug; it should only print the data given to write.

dinoboff commented 7 years ago

@RomansBermans It's fixed in upcoming 3.0.0 and 2.3.3 (with #93).

dinoboff commented 7 years ago

@RomansBermans I am closing this issue. The original issue was fix in 2.3.0 I think.

RomansBermans commented 7 years ago

@dinoboff thanks I will give it a go when 3.0.0 is released.