最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Firebase Error saving rules - Line 14: String can't contain ".", "#", "$&am

programmeradmin2浏览0评论

I hava a firebase realtime database in an app with the following format:

{
  "level_1": {
    "entry_01_06_2024_09_47_20_xw": {
      "co2_score": -276,
      "date": "01.06.2024",
      "date_in_milliseconds": 1717235240439,
      "level": 1,
      "name": "Name\n"
    },
    "entry_02_08_2024_12_10_23_xj": {
      "co2_score": 1780,
      "date": "02.08.2024",
      "date_in_milliseconds": 1722600623775,
      "level": 1,
      "name": "ab"
    },
    "entry_03_05_2024_13_54_06_gy": {
      "co2_score": 0,
      "date": "03.05.2024",
      "date_in_milliseconds": 1714744446791,
      "level": 1,
      "name": ""
    },
    "entry_03_05_2024_13_56_13_da": {
      "co2_score": 0,
      "date": "03.05.2024",
      "date_in_milliseconds": 1714744573164,
      "level": 1,
      "name": "5"
    },
    "entry_03_05_2024_14_00_30_ti": {
      "co2_score": 0,
      "date": "03.05.2024",
      "date_in_milliseconds": 1714744830661,
      "level": 1,
      "name": "m"
    },
    "entry_04_05_2024_13_34_06_sa": {
      "co2_score": 0,
      "date": "04.05.2024",
      "date_in_milliseconds": 1714829646967,
      "level": 1,
      "name": "Cheater\n"
    },
    "entry_04_05_2024_13_59_53_qw": {
      "co2_score": 273,
      "date": "04.05.2024",
      "date_in_milliseconds": 1714831193185,
      "level": 1,
      "name": "Tester"
    },
    "entry_04_05_2024_14_02_26_td": {
      "co2_score": 612,
      "date": "04.05.2024",
      "date_in_milliseconds": 1714831346600,
      "level": 1,
      "name": "x"
    },
    "entry_04_05_2024_14_04_23_cz": {
      "co2_score": -67,
      "date": "04.05.2024",
      "date_in_milliseconds": 1714831463165,
      "level": 1,
      "name": "Long name tester for the highscores"
    },
    "entry_04_05_2024_14_07_29_me": {
      "co2_score": 0,
      "date": "04.05.2024",
      "date_in_milliseconds": 1714831649683,
      "level": 1,
      "name": "this is now a test input for the highscore name to check what will be displayed if someone enters a nme with many characters. I want to check how thte CardView displayes the text in the textviews. "
    },
    "entry_04_11_2023_10_12_22": {
      "co2_score": 524,
      "date": "04.11.2023",
      "date_in_milliseconds": 1629183157853,
      "level": 1,
      "name": "Playeras"
    },
    "entry_04_11_2023_10_12_23": {
      "co2_score": 2158598,
      "date": "04.11.2023",
      "date_in_milliseconds": 1711188068615,
      "level": 1,
      "name": "Duffman"
    },
    "entry_05_06_2024_07_46_42_lg": {
      "co2_score": 40,
      "date": "05.06.2024",
      "date_in_milliseconds": 1717573602366,
      "level": 1,
      "name": "A"
    },
    "entry_05_06_2024_09_09_53_gu": {
      "co2_score": 287,
      "date": "05.06.2024",
      "date_in_milliseconds": 1717578593960,
      "level": 1,
      "name": "AADD"
    },
    "entry_09_01_2025_09_18_08_xn": {
      "co2_score": 14683,
      "date": "09.01.2025",
      "date_in_milliseconds": 1736414288672,
      "level": 1,
      "name": "Test"
    },
    "entry_09_07_2024_14_59_25_bs": {
      "co2_score": 21,
      "date": "09.07.2024",
      "date_in_milliseconds": 1720537165447,
      "level": 1,
      "name": "2"
    },
    "entry_12_07_2024_13_56_45_qt": {
      "co2_score": 244,
      "date": "12.07.2024",
      "date_in_milliseconds": 1720792605725,
      "level": 1,
      "name": "11"
    },
    "entry_12_07_2024_14_05_57_hk": {
      "co2_score": 47,
      "date": "12.07.2024",
      "date_in_milliseconds": 1720793157776,
      "level": 1,
      "name": "r"
    },
    "entry_12_07_2024_14_23_55_nc": {
      "co2_score": 65,
      "date": "12.07.2024",
      "date_in_milliseconds": 1720794235558,
      "level": 1,
      "name": "sse"
    },
    "entry_12_07_2024_14_27_19_su": {
      "co2_score": 102,
      "date": "12.07.2024",
      "date_in_milliseconds": 1720794439247,
      "level": 1,
      "name": "a"
    },
    "entry_12_07_2024_14_30_18_xa": {
      "co2_score": 48,
      "date": "12.07.2024",
      "date_in_milliseconds": 1720794618243,
      "level": 1,
      "name": "ii"
    },
    "entry_12_07_2024_14_34_52_sl": {
      "co2_score": 70,
      "date": "12.07.2024",
      "date_in_milliseconds": 1720794892726,
      "level": 1,
      "name": "tt"
    },
    "entry_12_07_2024_14_37_51_et": {
      "co2_score": 108,
      "date": "12.07.2024",
      "date_in_milliseconds": 1720795071044,
      "level": 1,
      "name": "Teste"
    },
    "entry_12_07_2024_14_40_05_cy": {
      "co2_score": 110,
      "date": "12.07.2024",
      "date_in_milliseconds": 1820795205322,
      "level": 1,
      "name": "Test2"
    },
    "entry_12_07_2024_14_41_47_fx": {
      "co2_score": 53,
      "date": "12.07.2024",
      "date_in_milliseconds": 1720795307575,
      "level": 1,
      "name": "aaa"
    },
    "entry_12_07_2024_14_44_41_cc": {
      "co2_score": 555,
      "date": "12.07.2024",
      "date_in_milliseconds": 1720795481761,
      "level": 1,
      "name": "252"
    },
    "entry_12_07_2024_14_45_53_zc": {
      "co2_score": 132,
      "date": "12.07.2024",
      "date_in_milliseconds": 1720795553474,
      "level": 1,
      "name": "der"
    },
    "entry_12_07_2024_14_46_57_hs": {
      "co2_score": 10,
      "date": "12.07.2024",
      "date_in_milliseconds": 1720795617554,
      "level": 1,
      "name": "dere"
    },
    "entry_12_10_2023_10_12_22": {
      "co2_score": 1142,
      "date": "04.11.2023",
      "date_in_milliseconds": 1667616006002,
      "level": 1,
      "name": "Player 92"
    },
    "entry_13_01_2025_13_25_22_wj": {
      "co2_score": 13024,
      "date": "13.01.2025",
      "date_in_milliseconds": 1736774722204,
      "level": 1,
      "name": "SS"
    },
    "entry_13_01_2025_13_27_47_ht": {
      "co2_score": 13180,
      "date": "13.01.2025",
      "date_in_milliseconds": 1736774867920,
      "level": 1,
      "name": "rr"
    },
    "entry_13_07_2024_08_51_38_fh": {
      "co2_score": 9,
      "date": "13.07.2024",
      "date_in_milliseconds": 1720860698181,
      "level": 1,
      "name": "Test1"
    },
    "entry_13_07_2024_08_55_28_yc": {
      "co2_score": 98,
      "date": "13.07.2024",
      "date_in_milliseconds": 1720860928099,
      "level": 1,
      "name": "Test_1"
    },
    "entry_13_07_2024_09_00_45_sr": {
      "co2_score": 137,
      "date": "13.07.2024",
      "date_in_milliseconds": 1720861245465,
      "level": 1,
      "name": "Test_2"
    },
    "entry_14_02_2025_08_28_38_sl": {
      "co2_score": 12419,
      "date": "14.02.2025",
      "date_in_milliseconds": 1739521718589,
      "level": 1,
      "name": "sd"
    },
    "entry_14_02_2025_08_34_52_mf": {
      "co2_score": 11310,
      "date": "14.02.2025",
      "date_in_milliseconds": 1739522092208,
      "level": 1,
      "name": "v"
    },
    "entry_16_03_2024_10_06_22": {
      "co2_score": 12335,
      "date": "16.03.2024",
      "date_in_milliseconds": 1650579987170,
      "level": 1,
      "name": "Chief Wiggum"
    },
    "entry_16_03_2024_10_07_12": {
      "co2_score": 1200,
      "date": "16.03.2024",
      "date_in_milliseconds": 1709074800000,
      "level": 1,
      "name": "Daddy Cool"
    },
    "entry_17_01_2025_10_47_21_fb": {
      "co2_score": 1834,
      "date": "17.01.2025",
      "date_in_milliseconds": 1737110841381,
      "level": 1,
      "name": "rrr"
    },
    "entry_18_01_2025_10_26_14_yn": {
      "co2_score": 6659,
      "date": "18.01.2025",
      "date_in_milliseconds": 1737195974571,
      "level": 1,
      "name": "Der"
    },
    "entry_19_02_2025_09_08_54_yv": {
      "co2_score": 11868,
      "date": "19.02.2025",
      "date_in_milliseconds": 1739956134738,
      "level": 1,
      "name": "DasIstER"
    },
    "entry_19_02_2025_15_25_04_pc": {
      "co2_score": 9365,
      "date": "19.02.2025",
      "date_in_milliseconds": 1739978704062,
      "level": 1,
      "name": "hhj"
    },
    "entry_19_11_2024_22_22_05_do": {
      "co2_score": 7114,
      "date": "19.11.2024",
      "date_in_milliseconds": 1732051325885,
      "level": 1,
      "name": "u"
    },
    "entry_21_06_2024_12_17_17_fq": {
      "co2_score": 380,
      "date": "21.06.2024",
      "date_in_milliseconds": 1718972237734,
      "level": 1,
      "name": "A"
    },
    "entry_24_04_2024_15_16_08_wo": {
      "co2_score": 0,
      "date": "24.04.2024",
      "date_in_milliseconds": 1713971768223,
      "level": 1,
      "name": "d"
    },
    "entry_24_04_2024_15_24_29_he": {
      "co2_score": 0,
      "date": "24.04.2024",
      "date_in_milliseconds": 1713972269254,
      "level": 1,
      "name": "z"
    },
    "entry_24_04_2024_15_25_39_mg": {
      "co2_score": 0,
      "date": "24.04.2024",
      "date_in_milliseconds": 1713972339936,
      "level": 1,
      "name": "x"
    },
    "entry_26_04_2024_13_07_50_dt": {
      "co2_score": 0,
      "date": "26.04.2024",
      "date_in_milliseconds": 1714136870212,
      "level": 1,
      "name": "22"
    },
    "entry_26_07_2024_13_43_59_ve": {
      "co2_score": 12576,
      "date": "26.07.2024",
      "date_in_milliseconds": 1722001439402,
      "level": 1,
      "name": "ttt"
    },
    "entry_26_10_2024_09_38_24_kt": {
      "co2_score": 7063,
      "date": "26.10.2024",
      "date_in_milliseconds": 1729935504606,
      "level": 1,
      "name": "T"
    }
  },
  "level_2": {
    "entry_04_11_2023_10_12_22": {
      "co2_score": 427,
      "date": "04.11.2023",
      "date_in_milliseconds": 1667616002000,
      "level": 2,
      "name": "Player 1"
    },
    "entry_04_11_2023_10_12_23": {
      "co2_score": 156,
      "date": "04.11.2023",
      "date_in_milliseconds": 1667616007000,
      "level": 2,
      "name": "G-Style"
    },
    "entry_09_07_2024_14_53_47_es": {
      "co2_score": -162,
      "date": "09.07.2024",
      "date_in_milliseconds": 1720536827619,
      "level": 2,
      "name": "5\n"
    },
    "entry_12_10_2023_10_12_22": {
      "co2_score": 542,
      "date": "04.11.2023",
      "date_in_milliseconds": 1667616008000,
      "level": 2,
      "name": "Perk"
    },
    "entry_29_10_2024_09_40_57_sf": {
      "co2_score": 14304,
      "date": "29.10.2024",
      "date_in_milliseconds": 1730194857390,
      "level": 2,
      "name": ""
    }
  },
  "level_4": {
    "entry_07_09_2024_10_20_32_rl": {
      "co2_score": 5796,
      "date": "07.09.2024",
      "date_in_milliseconds": 1725704432763,
      "level": 4,
      "name": "Level 4\n\n"
    }
  },
  "level_5": {
    "entry_14_03_2025_14_42_11_rv": {
      "co2_score": 467,
      "date": "14.03.2025",
      "date_in_milliseconds": 1741963331482,
      "level": 5,
      "name": "Test"
    },
    "entry_14_03_2025_14_43_21_pr": {
      "co2_score": 0,
      "date": "14.03.2025",
      "date_in_milliseconds": 1741963401267,
      "level": 5,
      "name": ""
    }
  },
  "level_6": {
    "entry_17_03_2025_13_58_28_fx": {
      "co2_score": 121,
      "date": "17.03.2025",
      "date_in_milliseconds": 1742219908865,
      "level": 6,
      "name": "s"
    }
  }
}

for an Android App game (with 8 or more levels). It is for reading and submitting highscores. When not using any security rules (or the default ones) everything works fine. But as I want to publish the app (maybe even on github) i want to make sure that

  1. Everyone can read the data

  2. everone can insert new data,

  3. noone can modify existing data (except for the admin)

  4. every inserted datapoint must have a certain structure regarding entries and type. For that I use the following code:

    {
      "rules": {
        "level_$level_number": {
          "$entry": {
            ".read": true,
            ".write": "!data.exists()",
            ".validate": "newData.hasChildren(['co2_score', 'date', 'date_in_milliseconds', 'level', 'name']) &&
                          newData.child('co2_score').isNumber() &&
                          newData.child('date').isString() &&
                        newData.child('date_in_milliseconds').isNumber() &&
                          newData.child('level').isNumber() &&
                          newData.child('name').isString()"
          }
        },
        ".read": false,
        ".write": false
      }
    }
    

But unfortunately I get the error:

Error saving rules - Line 14: String can't contain ".", "#", "$", "/", "[", or "]"

I tried many approach and always get similar errors. Can someone help me?

Update: Based on the answer of Frank, I tried to use this secury rules code:

{
  "rules": {
    "level_number": {
      "$level": {
        "$entry": {
          ".read": true,
          ".write": "!data.exists()",
          ".validate": "newData.hasChildren(['co2_score', 'date', 'date_in_milliseconds', 'level', 'name']) &&
                      newData.child('co2_score').isNumber() &&
                      newData.child('date').isString() &&
                      newData.child('date_in_milliseconds').isNumber() &&
                      newData.child('level').isNumber() &&
                      newData.child('name').isString()"
        }
      },
      ".read": false,
      ".write": false
    }
  }
}

Here is the java code I execute for reading the data:

private void checkHighScore(double co2SavingsScoreCurrentRun) {
    //Firebase query to get all Highscores for this level
    long millisecondsThresholdLastWeek = System.currentTimeMillis() -  (7 * 24L * 60 * 60 * 1000);
    long millisecondsThresholdLastMonth = System.currentTimeMillis() -  (30 * 24L * 60 * 60 * 1000);
    long millisecondsThresholdOverall = 0;

    ArrayList<RV_Item_Highscore> arrayList_HighScore_LastWeek = new ArrayList<>();
    ArrayList<RV_Item_Highscore> arrayList_HighScore_LastMonth = new ArrayList<>();
    ArrayList<RV_Item_Highscore> arrayList_HighScore_Overall = new ArrayList<>();

    String firebaseNodeLevel = "level_" + currentLevel;
    rootRef_Firebase.child(firebaseNodeLevel).orderByChild(FIREBASE_DATE_IN_MILLISECONDS).addListenerForSingleValueEvent(new ValueEventListener() {
        @SuppressLint("SetTextI18n")
        @Override
        public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
            //Find out position of the current co2SavingsScoreCurrentRun regarding all entries for the week, month and overall
            for (DataSnapshot ds : dataSnapshot.getChildren()) {
                String name = ds.child(FIREBASE_NAME).getValue(String.class);

                // Use a default value if co2ScoreHighScoreEntry is null
                Integer co2ScoreHighScoreEntry = ds.child(FIREBASE_CO_2_SCORE).getValue(Integer.class);
                int co2Score = (co2ScoreHighScoreEntry != null) ? co2ScoreHighScoreEntry : 0;  // Default to 0 if null

                String date = ds.child(FIREBASE_DATE).getValue(String.class);

                // Use a default value if level is null
                Integer level = ds.child(FIREBASE_LEVEL).getValue(Integer.class);
                int levelValue = (level != null) ? level : 0;  // Default to 0 if null

                // Use a default value if dateInMillisecondsFirebaseEntryLong is null
                Long dateInMillisecondsFirebaseEntryLong = ds.child(FIREBASE_DATE_IN_MILLISECONDS).getValue(Long.class);
                long dateInMilliseconds = (dateInMillisecondsFirebaseEntryLong != null) ? dateInMillisecondsFirebaseEntryLong : 0L;  // Default to 0L if null

                Log.e("Tag_Dialog", "Highscore iteration name:" + name);

                if (dateInMilliseconds > millisecondsThresholdLastWeek) {
                    arrayList_HighScore_LastWeek.add(new RV_Item_Highscore(name, co2Score, date, levelValue, 0));
                }

                if (dateInMilliseconds > millisecondsThresholdLastMonth) {
                    arrayList_HighScore_LastMonth.add(new RV_Item_Highscore(name, co2Score, date, levelValue, 0));
                }

                if (dateInMilliseconds > millisecondsThresholdOverall) {
                    arrayList_HighScore_Overall.add(new RV_Item_Highscore(name, co2Score, date, levelValue, 0));
                }
            }

            //Filter the data to calculate the positions for this week, month and overall
            int positionOfCurrentScoreInHishScoreListLastWeek = 1;
            int positionOfCurrentScoreInHishScoreListLastMonth = 1;
            int positionOfCurrentScoreInHishScoreListOverall = 1;

            for (int i = 0; i < arrayList_HighScore_LastWeek.size(); i++) {
                RV_Item_Highscore item = arrayList_HighScore_LastWeek.get(i);
                if (item.getCo2Score() > co2SavingsScoreCurrentRun) {
                    positionOfCurrentScoreInHishScoreListLastWeek++;
                }
            }

            for (int i = 0; i < arrayList_HighScore_LastMonth.size(); i++) {
                RV_Item_Highscore item = arrayList_HighScore_LastMonth.get(i);
                if (item.getCo2Score() > co2SavingsScoreCurrentRun) {
                    positionOfCurrentScoreInHishScoreListLastMonth++;
                }
            }

            for (int i = 0; i < arrayList_HighScore_Overall.size(); i++) {
                RV_Item_Highscore item = arrayList_HighScore_Overall.get(i);
                if (item.getCo2Score() > co2SavingsScoreCurrentRun) {
                    positionOfCurrentScoreInHishScoreListOverall++;
                }
            }

            if (FR_Options.getLanguage(requireContext()).equals("de")) {
                String text = "Position " + positionOfCurrentScoreInHishScoreListLastWeek + " letzte Woche\n"
                        + "Position " + positionOfCurrentScoreInHishScoreListLastMonth + " letzten Monat";
                if (positionOfCurrentScoreInHishScoreListOverall <= 10) {
                    text += "\nPosition " + positionOfCurrentScoreInHishScoreListOverall + " insgesamt";
                }
                binding.textViewHighscoreMessagePositions.setText(text);
            } else {
                String text = "Position " + positionOfCurrentScoreInHishScoreListLastWeek + " last Week\n"
                        + "Position " + positionOfCurrentScoreInHishScoreListLastMonth + " last Month";
                if (positionOfCurrentScoreInHishScoreListOverall <= 10) {
                    text += "\nPosition " + positionOfCurrentScoreInHishScoreListOverall + " overall";
                }
                binding.textViewHighscoreMessagePositions.setText(text);
            }

            //If the current score is in the top 10 in one category, display the "Submit" button and handle the clicking event:
            if (positionOfCurrentScoreInHishScoreListLastWeek<=10) {
                binding.buttonSubmit.setEnabled(true);
                binding.buttonSubmit.setClickable(true);
                binding.buttonSubmit.setAlpha(1.0f);
            }
        }

        @Override
        public void onCancelled(@NonNull DatabaseError databaseError) {
            // Handle potential errors here
        }
    });
}

Without any security rules (or just the default ones with true access to read and write) it works as expected. But with the suggested security rules by Frank, it does not work.

Unfortunately when using this code nobody can read and write data anymore through my app.

I hava a firebase realtime database in an app with the following format:

{
  "level_1": {
    "entry_01_06_2024_09_47_20_xw": {
      "co2_score": -276,
      "date": "01.06.2024",
      "date_in_milliseconds": 1717235240439,
      "level": 1,
      "name": "Name\n"
    },
    "entry_02_08_2024_12_10_23_xj": {
      "co2_score": 1780,
      "date": "02.08.2024",
      "date_in_milliseconds": 1722600623775,
      "level": 1,
      "name": "ab"
    },
    "entry_03_05_2024_13_54_06_gy": {
      "co2_score": 0,
      "date": "03.05.2024",
      "date_in_milliseconds": 1714744446791,
      "level": 1,
      "name": ""
    },
    "entry_03_05_2024_13_56_13_da": {
      "co2_score": 0,
      "date": "03.05.2024",
      "date_in_milliseconds": 1714744573164,
      "level": 1,
      "name": "5"
    },
    "entry_03_05_2024_14_00_30_ti": {
      "co2_score": 0,
      "date": "03.05.2024",
      "date_in_milliseconds": 1714744830661,
      "level": 1,
      "name": "m"
    },
    "entry_04_05_2024_13_34_06_sa": {
      "co2_score": 0,
      "date": "04.05.2024",
      "date_in_milliseconds": 1714829646967,
      "level": 1,
      "name": "Cheater\n"
    },
    "entry_04_05_2024_13_59_53_qw": {
      "co2_score": 273,
      "date": "04.05.2024",
      "date_in_milliseconds": 1714831193185,
      "level": 1,
      "name": "Tester"
    },
    "entry_04_05_2024_14_02_26_td": {
      "co2_score": 612,
      "date": "04.05.2024",
      "date_in_milliseconds": 1714831346600,
      "level": 1,
      "name": "x"
    },
    "entry_04_05_2024_14_04_23_cz": {
      "co2_score": -67,
      "date": "04.05.2024",
      "date_in_milliseconds": 1714831463165,
      "level": 1,
      "name": "Long name tester for the highscores"
    },
    "entry_04_05_2024_14_07_29_me": {
      "co2_score": 0,
      "date": "04.05.2024",
      "date_in_milliseconds": 1714831649683,
      "level": 1,
      "name": "this is now a test input for the highscore name to check what will be displayed if someone enters a nme with many characters. I want to check how thte CardView displayes the text in the textviews. "
    },
    "entry_04_11_2023_10_12_22": {
      "co2_score": 524,
      "date": "04.11.2023",
      "date_in_milliseconds": 1629183157853,
      "level": 1,
      "name": "Playeras"
    },
    "entry_04_11_2023_10_12_23": {
      "co2_score": 2158598,
      "date": "04.11.2023",
      "date_in_milliseconds": 1711188068615,
      "level": 1,
      "name": "Duffman"
    },
    "entry_05_06_2024_07_46_42_lg": {
      "co2_score": 40,
      "date": "05.06.2024",
      "date_in_milliseconds": 1717573602366,
      "level": 1,
      "name": "A"
    },
    "entry_05_06_2024_09_09_53_gu": {
      "co2_score": 287,
      "date": "05.06.2024",
      "date_in_milliseconds": 1717578593960,
      "level": 1,
      "name": "AADD"
    },
    "entry_09_01_2025_09_18_08_xn": {
      "co2_score": 14683,
      "date": "09.01.2025",
      "date_in_milliseconds": 1736414288672,
      "level": 1,
      "name": "Test"
    },
    "entry_09_07_2024_14_59_25_bs": {
      "co2_score": 21,
      "date": "09.07.2024",
      "date_in_milliseconds": 1720537165447,
      "level": 1,
      "name": "2"
    },
    "entry_12_07_2024_13_56_45_qt": {
      "co2_score": 244,
      "date": "12.07.2024",
      "date_in_milliseconds": 1720792605725,
      "level": 1,
      "name": "11"
    },
    "entry_12_07_2024_14_05_57_hk": {
      "co2_score": 47,
      "date": "12.07.2024",
      "date_in_milliseconds": 1720793157776,
      "level": 1,
      "name": "r"
    },
    "entry_12_07_2024_14_23_55_nc": {
      "co2_score": 65,
      "date": "12.07.2024",
      "date_in_milliseconds": 1720794235558,
      "level": 1,
      "name": "sse"
    },
    "entry_12_07_2024_14_27_19_su": {
      "co2_score": 102,
      "date": "12.07.2024",
      "date_in_milliseconds": 1720794439247,
      "level": 1,
      "name": "a"
    },
    "entry_12_07_2024_14_30_18_xa": {
      "co2_score": 48,
      "date": "12.07.2024",
      "date_in_milliseconds": 1720794618243,
      "level": 1,
      "name": "ii"
    },
    "entry_12_07_2024_14_34_52_sl": {
      "co2_score": 70,
      "date": "12.07.2024",
      "date_in_milliseconds": 1720794892726,
      "level": 1,
      "name": "tt"
    },
    "entry_12_07_2024_14_37_51_et": {
      "co2_score": 108,
      "date": "12.07.2024",
      "date_in_milliseconds": 1720795071044,
      "level": 1,
      "name": "Teste"
    },
    "entry_12_07_2024_14_40_05_cy": {
      "co2_score": 110,
      "date": "12.07.2024",
      "date_in_milliseconds": 1820795205322,
      "level": 1,
      "name": "Test2"
    },
    "entry_12_07_2024_14_41_47_fx": {
      "co2_score": 53,
      "date": "12.07.2024",
      "date_in_milliseconds": 1720795307575,
      "level": 1,
      "name": "aaa"
    },
    "entry_12_07_2024_14_44_41_cc": {
      "co2_score": 555,
      "date": "12.07.2024",
      "date_in_milliseconds": 1720795481761,
      "level": 1,
      "name": "252"
    },
    "entry_12_07_2024_14_45_53_zc": {
      "co2_score": 132,
      "date": "12.07.2024",
      "date_in_milliseconds": 1720795553474,
      "level": 1,
      "name": "der"
    },
    "entry_12_07_2024_14_46_57_hs": {
      "co2_score": 10,
      "date": "12.07.2024",
      "date_in_milliseconds": 1720795617554,
      "level": 1,
      "name": "dere"
    },
    "entry_12_10_2023_10_12_22": {
      "co2_score": 1142,
      "date": "04.11.2023",
      "date_in_milliseconds": 1667616006002,
      "level": 1,
      "name": "Player 92"
    },
    "entry_13_01_2025_13_25_22_wj": {
      "co2_score": 13024,
      "date": "13.01.2025",
      "date_in_milliseconds": 1736774722204,
      "level": 1,
      "name": "SS"
    },
    "entry_13_01_2025_13_27_47_ht": {
      "co2_score": 13180,
      "date": "13.01.2025",
      "date_in_milliseconds": 1736774867920,
      "level": 1,
      "name": "rr"
    },
    "entry_13_07_2024_08_51_38_fh": {
      "co2_score": 9,
      "date": "13.07.2024",
      "date_in_milliseconds": 1720860698181,
      "level": 1,
      "name": "Test1"
    },
    "entry_13_07_2024_08_55_28_yc": {
      "co2_score": 98,
      "date": "13.07.2024",
      "date_in_milliseconds": 1720860928099,
      "level": 1,
      "name": "Test_1"
    },
    "entry_13_07_2024_09_00_45_sr": {
      "co2_score": 137,
      "date": "13.07.2024",
      "date_in_milliseconds": 1720861245465,
      "level": 1,
      "name": "Test_2"
    },
    "entry_14_02_2025_08_28_38_sl": {
      "co2_score": 12419,
      "date": "14.02.2025",
      "date_in_milliseconds": 1739521718589,
      "level": 1,
      "name": "sd"
    },
    "entry_14_02_2025_08_34_52_mf": {
      "co2_score": 11310,
      "date": "14.02.2025",
      "date_in_milliseconds": 1739522092208,
      "level": 1,
      "name": "v"
    },
    "entry_16_03_2024_10_06_22": {
      "co2_score": 12335,
      "date": "16.03.2024",
      "date_in_milliseconds": 1650579987170,
      "level": 1,
      "name": "Chief Wiggum"
    },
    "entry_16_03_2024_10_07_12": {
      "co2_score": 1200,
      "date": "16.03.2024",
      "date_in_milliseconds": 1709074800000,
      "level": 1,
      "name": "Daddy Cool"
    },
    "entry_17_01_2025_10_47_21_fb": {
      "co2_score": 1834,
      "date": "17.01.2025",
      "date_in_milliseconds": 1737110841381,
      "level": 1,
      "name": "rrr"
    },
    "entry_18_01_2025_10_26_14_yn": {
      "co2_score": 6659,
      "date": "18.01.2025",
      "date_in_milliseconds": 1737195974571,
      "level": 1,
      "name": "Der"
    },
    "entry_19_02_2025_09_08_54_yv": {
      "co2_score": 11868,
      "date": "19.02.2025",
      "date_in_milliseconds": 1739956134738,
      "level": 1,
      "name": "DasIstER"
    },
    "entry_19_02_2025_15_25_04_pc": {
      "co2_score": 9365,
      "date": "19.02.2025",
      "date_in_milliseconds": 1739978704062,
      "level": 1,
      "name": "hhj"
    },
    "entry_19_11_2024_22_22_05_do": {
      "co2_score": 7114,
      "date": "19.11.2024",
      "date_in_milliseconds": 1732051325885,
      "level": 1,
      "name": "u"
    },
    "entry_21_06_2024_12_17_17_fq": {
      "co2_score": 380,
      "date": "21.06.2024",
      "date_in_milliseconds": 1718972237734,
      "level": 1,
      "name": "A"
    },
    "entry_24_04_2024_15_16_08_wo": {
      "co2_score": 0,
      "date": "24.04.2024",
      "date_in_milliseconds": 1713971768223,
      "level": 1,
      "name": "d"
    },
    "entry_24_04_2024_15_24_29_he": {
      "co2_score": 0,
      "date": "24.04.2024",
      "date_in_milliseconds": 1713972269254,
      "level": 1,
      "name": "z"
    },
    "entry_24_04_2024_15_25_39_mg": {
      "co2_score": 0,
      "date": "24.04.2024",
      "date_in_milliseconds": 1713972339936,
      "level": 1,
      "name": "x"
    },
    "entry_26_04_2024_13_07_50_dt": {
      "co2_score": 0,
      "date": "26.04.2024",
      "date_in_milliseconds": 1714136870212,
      "level": 1,
      "name": "22"
    },
    "entry_26_07_2024_13_43_59_ve": {
      "co2_score": 12576,
      "date": "26.07.2024",
      "date_in_milliseconds": 1722001439402,
      "level": 1,
      "name": "ttt"
    },
    "entry_26_10_2024_09_38_24_kt": {
      "co2_score": 7063,
      "date": "26.10.2024",
      "date_in_milliseconds": 1729935504606,
      "level": 1,
      "name": "T"
    }
  },
  "level_2": {
    "entry_04_11_2023_10_12_22": {
      "co2_score": 427,
      "date": "04.11.2023",
      "date_in_milliseconds": 1667616002000,
      "level": 2,
      "name": "Player 1"
    },
    "entry_04_11_2023_10_12_23": {
      "co2_score": 156,
      "date": "04.11.2023",
      "date_in_milliseconds": 1667616007000,
      "level": 2,
      "name": "G-Style"
    },
    "entry_09_07_2024_14_53_47_es": {
      "co2_score": -162,
      "date": "09.07.2024",
      "date_in_milliseconds": 1720536827619,
      "level": 2,
      "name": "5\n"
    },
    "entry_12_10_2023_10_12_22": {
      "co2_score": 542,
      "date": "04.11.2023",
      "date_in_milliseconds": 1667616008000,
      "level": 2,
      "name": "Perk"
    },
    "entry_29_10_2024_09_40_57_sf": {
      "co2_score": 14304,
      "date": "29.10.2024",
      "date_in_milliseconds": 1730194857390,
      "level": 2,
      "name": ""
    }
  },
  "level_4": {
    "entry_07_09_2024_10_20_32_rl": {
      "co2_score": 5796,
      "date": "07.09.2024",
      "date_in_milliseconds": 1725704432763,
      "level": 4,
      "name": "Level 4\n\n"
    }
  },
  "level_5": {
    "entry_14_03_2025_14_42_11_rv": {
      "co2_score": 467,
      "date": "14.03.2025",
      "date_in_milliseconds": 1741963331482,
      "level": 5,
      "name": "Test"
    },
    "entry_14_03_2025_14_43_21_pr": {
      "co2_score": 0,
      "date": "14.03.2025",
      "date_in_milliseconds": 1741963401267,
      "level": 5,
      "name": ""
    }
  },
  "level_6": {
    "entry_17_03_2025_13_58_28_fx": {
      "co2_score": 121,
      "date": "17.03.2025",
      "date_in_milliseconds": 1742219908865,
      "level": 6,
      "name": "s"
    }
  }
}

for an Android App game (with 8 or more levels). It is for reading and submitting highscores. When not using any security rules (or the default ones) everything works fine. But as I want to publish the app (maybe even on github) i want to make sure that

  1. Everyone can read the data

  2. everone can insert new data,

  3. noone can modify existing data (except for the admin)

  4. every inserted datapoint must have a certain structure regarding entries and type. For that I use the following code:

    {
      "rules": {
        "level_$level_number": {
          "$entry": {
            ".read": true,
            ".write": "!data.exists()",
            ".validate": "newData.hasChildren(['co2_score', 'date', 'date_in_milliseconds', 'level', 'name']) &&
                          newData.child('co2_score').isNumber() &&
                          newData.child('date').isString() &&
                        newData.child('date_in_milliseconds').isNumber() &&
                          newData.child('level').isNumber() &&
                          newData.child('name').isString()"
          }
        },
        ".read": false,
        ".write": false
      }
    }
    

But unfortunately I get the error:

Error saving rules - Line 14: String can't contain ".", "#", "$", "/", "[", or "]"

I tried many approach and always get similar errors. Can someone help me?

Update: Based on the answer of Frank, I tried to use this secury rules code:

{
  "rules": {
    "level_number": {
      "$level": {
        "$entry": {
          ".read": true,
          ".write": "!data.exists()",
          ".validate": "newData.hasChildren(['co2_score', 'date', 'date_in_milliseconds', 'level', 'name']) &&
                      newData.child('co2_score').isNumber() &&
                      newData.child('date').isString() &&
                      newData.child('date_in_milliseconds').isNumber() &&
                      newData.child('level').isNumber() &&
                      newData.child('name').isString()"
        }
      },
      ".read": false,
      ".write": false
    }
  }
}

Here is the java code I execute for reading the data:

private void checkHighScore(double co2SavingsScoreCurrentRun) {
    //Firebase query to get all Highscores for this level
    long millisecondsThresholdLastWeek = System.currentTimeMillis() -  (7 * 24L * 60 * 60 * 1000);
    long millisecondsThresholdLastMonth = System.currentTimeMillis() -  (30 * 24L * 60 * 60 * 1000);
    long millisecondsThresholdOverall = 0;

    ArrayList<RV_Item_Highscore> arrayList_HighScore_LastWeek = new ArrayList<>();
    ArrayList<RV_Item_Highscore> arrayList_HighScore_LastMonth = new ArrayList<>();
    ArrayList<RV_Item_Highscore> arrayList_HighScore_Overall = new ArrayList<>();

    String firebaseNodeLevel = "level_" + currentLevel;
    rootRef_Firebase.child(firebaseNodeLevel).orderByChild(FIREBASE_DATE_IN_MILLISECONDS).addListenerForSingleValueEvent(new ValueEventListener() {
        @SuppressLint("SetTextI18n")
        @Override
        public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
            //Find out position of the current co2SavingsScoreCurrentRun regarding all entries for the week, month and overall
            for (DataSnapshot ds : dataSnapshot.getChildren()) {
                String name = ds.child(FIREBASE_NAME).getValue(String.class);

                // Use a default value if co2ScoreHighScoreEntry is null
                Integer co2ScoreHighScoreEntry = ds.child(FIREBASE_CO_2_SCORE).getValue(Integer.class);
                int co2Score = (co2ScoreHighScoreEntry != null) ? co2ScoreHighScoreEntry : 0;  // Default to 0 if null

                String date = ds.child(FIREBASE_DATE).getValue(String.class);

                // Use a default value if level is null
                Integer level = ds.child(FIREBASE_LEVEL).getValue(Integer.class);
                int levelValue = (level != null) ? level : 0;  // Default to 0 if null

                // Use a default value if dateInMillisecondsFirebaseEntryLong is null
                Long dateInMillisecondsFirebaseEntryLong = ds.child(FIREBASE_DATE_IN_MILLISECONDS).getValue(Long.class);
                long dateInMilliseconds = (dateInMillisecondsFirebaseEntryLong != null) ? dateInMillisecondsFirebaseEntryLong : 0L;  // Default to 0L if null

                Log.e("Tag_Dialog", "Highscore iteration name:" + name);

                if (dateInMilliseconds > millisecondsThresholdLastWeek) {
                    arrayList_HighScore_LastWeek.add(new RV_Item_Highscore(name, co2Score, date, levelValue, 0));
                }

                if (dateInMilliseconds > millisecondsThresholdLastMonth) {
                    arrayList_HighScore_LastMonth.add(new RV_Item_Highscore(name, co2Score, date, levelValue, 0));
                }

                if (dateInMilliseconds > millisecondsThresholdOverall) {
                    arrayList_HighScore_Overall.add(new RV_Item_Highscore(name, co2Score, date, levelValue, 0));
                }
            }

            //Filter the data to calculate the positions for this week, month and overall
            int positionOfCurrentScoreInHishScoreListLastWeek = 1;
            int positionOfCurrentScoreInHishScoreListLastMonth = 1;
            int positionOfCurrentScoreInHishScoreListOverall = 1;

            for (int i = 0; i < arrayList_HighScore_LastWeek.size(); i++) {
                RV_Item_Highscore item = arrayList_HighScore_LastWeek.get(i);
                if (item.getCo2Score() > co2SavingsScoreCurrentRun) {
                    positionOfCurrentScoreInHishScoreListLastWeek++;
                }
            }

            for (int i = 0; i < arrayList_HighScore_LastMonth.size(); i++) {
                RV_Item_Highscore item = arrayList_HighScore_LastMonth.get(i);
                if (item.getCo2Score() > co2SavingsScoreCurrentRun) {
                    positionOfCurrentScoreInHishScoreListLastMonth++;
                }
            }

            for (int i = 0; i < arrayList_HighScore_Overall.size(); i++) {
                RV_Item_Highscore item = arrayList_HighScore_Overall.get(i);
                if (item.getCo2Score() > co2SavingsScoreCurrentRun) {
                    positionOfCurrentScoreInHishScoreListOverall++;
                }
            }

            if (FR_Options.getLanguage(requireContext()).equals("de")) {
                String text = "Position " + positionOfCurrentScoreInHishScoreListLastWeek + " letzte Woche\n"
                        + "Position " + positionOfCurrentScoreInHishScoreListLastMonth + " letzten Monat";
                if (positionOfCurrentScoreInHishScoreListOverall <= 10) {
                    text += "\nPosition " + positionOfCurrentScoreInHishScoreListOverall + " insgesamt";
                }
                binding.textViewHighscoreMessagePositions.setText(text);
            } else {
                String text = "Position " + positionOfCurrentScoreInHishScoreListLastWeek + " last Week\n"
                        + "Position " + positionOfCurrentScoreInHishScoreListLastMonth + " last Month";
                if (positionOfCurrentScoreInHishScoreListOverall <= 10) {
                    text += "\nPosition " + positionOfCurrentScoreInHishScoreListOverall + " overall";
                }
                binding.textViewHighscoreMessagePositions.setText(text);
            }

            //If the current score is in the top 10 in one category, display the "Submit" button and handle the clicking event:
            if (positionOfCurrentScoreInHishScoreListLastWeek<=10) {
                binding.buttonSubmit.setEnabled(true);
                binding.buttonSubmit.setClickable(true);
                binding.buttonSubmit.setAlpha(1.0f);
            }
        }

        @Override
        public void onCancelled(@NonNull DatabaseError databaseError) {
            // Handle potential errors here
        }
    });
}

Without any security rules (or just the default ones with true access to read and write) it works as expected. But with the suggested security rules by Frank, it does not work.

Unfortunately when using this code nobody can read and write data anymore through my app.

Share Improve this question edited Mar 22 at 14:06 Frank van Puffelen 601k85 gold badges890 silver badges860 bronze badges Recognized by Google Cloud Collective asked Mar 17 at 14:47 VanessaFVanessaF 7952 gold badges17 silver badges48 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 0

This in your rules is not possible:

{
  "rules": {
    "level_$level_number": { // 
发布评论

评论列表(0)

  1. 暂无评论