Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit dbb6693

Browse files
committedFeb 13, 2025·
Fix Firbase Storage upload path issue #219
1 parent ad51419 commit dbb6693

File tree

6 files changed

+52
-53
lines changed

6 files changed

+52
-53
lines changed
 

‎README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

33
![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/mobizt/FirebaseClient/.github%2Fworkflows%2Fcompile_library.yml?logo=github&label=compile) [![Github Stars](https://img.shields.io/github/stars/mobizt/FirebaseClient?logo=github)](https://github.com/mobizt/FirebaseClient/stargazers) ![Github Issues](https://img.shields.io/github/issues/mobizt/FirebaseClient?logo=github)
44

5-
![GitHub Release](https://img.shields.io/github/v/release/mobizt/FirebaseClient) ![Arduino](https://img.shields.io/badge/Arduino-v1.5.10-57C207?logo=arduino) ![PlatformIO](https://badges.registry.platformio.org/packages/mobizt/library/FirebaseClient.svg) ![GitHub Release Date](https://img.shields.io/github/release-date/mobizt/FirebaseClient)
5+
![GitHub Release](https://img.shields.io/github/v/release/mobizt/FirebaseClient) ![Arduino](https://img.shields.io/badge/Arduino-v1.5.11-57C207?logo=arduino) ![PlatformIO](https://badges.registry.platformio.org/packages/mobizt/library/FirebaseClient.svg) ![GitHub Release Date](https://img.shields.io/github/release-date/mobizt/FirebaseClient)
66

77
[![GitHub Sponsors](https://img.shields.io/github/sponsors/mobizt?logo=github)](https://github.com/sponsors/mobizt)
88

9-
Revision `2025-02-12`
9+
Revision `2025-02-13`
1010

1111
## Table of Contents
1212

‎examples/RealtimeDatabase/Sync/CustomClaims/CustomClaims.ino

Lines changed: 44 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ void authHandler();
7575

7676
void printResult(AsyncResult &aResult);
7777

78-
bool mofifyRules(const String &parentPath, const String &node, const String &readCondition, const String &writeCondition, const String &databaseSecret);
78+
bool mofifyRules(const String &controlPath, const String &readCondition, const String &writeCondition, const String &databaseSecret);
7979

8080
void printError(int code, const String &msg);
8181

@@ -85,7 +85,7 @@ String genUUID();
8585

8686
DefaultNetwork network;
8787

88-
CustomAuth custom_auth(timeStatusCB, API_KEY, FIREBASE_CLIENT_EMAIL, FIREBASE_PROJECT_ID, PRIVATE_KEY, "Node1" /* UID */, "" /* claims can be set later */, 3600 /* expire period in seconds (<3600) */);
88+
CustomAuth custom_auth(timeStatusCB, API_KEY, FIREBASE_CLIENT_EMAIL, FIREBASE_PROJECT_ID, PRIVATE_KEY, "peter" /* UID */, "" /* claims can be set later */, 3600 /* expire period in seconds (<3600) */);
8989

9090
FirebaseApp app;
9191

@@ -140,29 +140,25 @@ void setup()
140140
// Here is the final security rules we want to set in this example.
141141
//
142142
// {
143-
// "rules": {
144-
// ...
145-
//
146-
// ...
147-
// "UsersData": {
148-
// "$userId": {
149-
// ".read": "($userId === auth.uid && auth.token.premium_account === true && auth.token.admin === true && auth.token.foo === 'bar')",
150-
// ".write": "($userId === auth.uid && auth.token.premium_account === true && auth.token.admin === true && auth.token.foo === 'bar')"
151-
// }
152-
// }
153-
// }
143+
// "rules": {
144+
// "logs": {
145+
// "database": {
146+
// "$resource": {
147+
// "$group": {
148+
// "$userId": {
149+
// ".read": "($userId === auth.uid && auth.token.resource === $resource && auth.token.group === $group)",
150+
// ".write": "($userId === auth.uid && auth.token.resource === $resource && auth.token.group === $group)"
151+
// }
152+
// }
153+
// }
154+
// }
155+
// }
156+
// }
154157
// }
155158
//
156-
// We use $ variable in the rules e.g. #userId to capture the path segment. If we access database at /UserData/xyz, the xyz well be our $userId variable in the rules.
157-
// When the $userId was used in the condition e.g. "$userId === auth.uid", the result will be false for this xyz UID case.
158-
// This will allow us to access the database only at /UserData/Node1.
159-
// Then the user with provided UID e.g. xyz can only access to database at /UserData/xyz because the UID obtains from auth.uid variable
160-
// matches the path segment variable $userId.
161-
//
162-
// In our rules above at the path UsersData/$userId, other auth variables are also checked
163-
// i.e. auth.token which the admin's, premium_account's and foo's values are checked for maching.
164-
// If one of these condition is false, the access to UsersData/$userId will be denied.
165-
// The auth.token.??? is variable that taken from the ID token's claims.
159+
// We use $ variable in the rules e.g. $resource, $group, and $userId to capture the path segment that are used to compare with the auth variables
160+
// that we set e.g. $userId will be compared with UID (auth.uid), $resource will be compared with resource claim (auth.token.resource),
161+
// and $group will be compared with group claim (auth.token.group).
166162
//
167163
// For more information, visit https://firebase.google.com/docs/database/security/rules-conditions#using_variables_to_capture_path_segments
168164
//
@@ -178,19 +174,21 @@ void setup()
178174
// ".read": "some other conditions that allow access by date"
179175
// ".write": "some other conditions that allow access by date"
180176

181-
String parentPath = "/UsersData";
182-
String node = "$userId";
183-
String readConditions = "($userId === auth.uid && auth.token.premium_account === true && auth.token.admin === true && auth.token.foo === 'bar')";
177+
String controlPath = "/logs/database/$resource/$group/$userId";
178+
String readConditions = "($userId === auth.uid && auth.token.resource === $resource && auth.token.group === $group)";
184179
String writeConditions = readConditions;
185180

186-
mofifyRules(parentPath, node, readConditions, writeConditions, DATABASE_SECRET);
181+
mofifyRules(controlPath, readConditions, writeConditions, DATABASE_SECRET);
187182

188183
// We will set the claims to the token we used here (ID token using CustomAuth).
189-
// We set the values of the claims to math the auth.token varibles values in the security rules condition checking.
184+
// We set the values of the claims to math the auth.token varibles values in the security rules conditions.
190185
// The claims string must be JSON serialized string when passing to CustomAuth::setClaims or CustomAuth class constructor.
191186

192187
// For more details about custom claims, please see https://firebase.google.com/docs/auth/admin/custom-claims.
193-
String claims = "{\"premium_account\": true,\"admin\": true, \"foo\":\"bar\"}";
188+
189+
// The resource claim value can be access via auth.token.resource in the security rules.
190+
// And group claim value can be access via auth.token.group.
191+
String claims = "{\"resource\":\"products\", \"group\":\"user\"}";
194192
custom_auth.setClaims(claims);
195193

196194
// Now we authenticate (sign in) with CustomAuth (ID token with custom UID and claims).
@@ -214,9 +212,13 @@ void loop()
214212
{
215213
ms = millis();
216214

217-
String path = "/UsersData/";
218-
path += app.getUid(); // Node1 is the UID that previously defind in CustomAuth constructor.
219-
path += "/test/int";
215+
// From the UID, claims and security rules we have set,
216+
// it only allows us to access at logs/database/products/user/peter/...
217+
// Because the resource in the claim is products and group claim is user.
218+
219+
String path = "logs/database/products/user/";
220+
path += app.getUid();
221+
path += "/value";
220222

221223
Serial.print("Setting the int value to the granted path... ");
222224
// This should be ok. Because we write to the path /UsersData/Node1/... which is allowed in the security rules.
@@ -303,13 +305,12 @@ void timeStatusCB(uint32_t &ts)
303305
}
304306

305307
/**
306-
* @param parent The parent path of child's node that the which we want to control access.
307-
* @param child The child node path which we want to control access.
308+
* @param controlPath The path that the which we want to control access.
308309
* @param readCondition The read access condition.
309310
* @param writeCondition The write access condition.
310311
* @param databaseSecret The database secret.
311312
*/
312-
bool mofifyRules(const String &parentPath, const String &child, const String &readCondition, const String &writeCondition, const String &databaseSecret)
313+
bool mofifyRules(const String &controlPath, const String &readCondition, const String &writeCondition, const String &databaseSecret)
313314
{
314315
// Use database secret for to allow security rules access.
315316
// The ServiceAuth (OAuth2.0 access token authorization) can also be used
@@ -336,18 +337,10 @@ bool mofifyRules(const String &parentPath, const String &child, const String &re
336337

337338
String rulePath = "rules";
338339

339-
if (parentPath.length() && parentPath[0] != '/')
340-
rulePath += '/';
341-
342-
rulePath += parentPath;
343-
344-
if (rulePath[rulePath.length() - 1] == '/')
345-
rulePath[rulePath.length() - 1] = 0;
346-
347-
if (child.length() && child[0] != '/' && rulePath[rulePath.length() - 1] != '/')
340+
if (controlPath.length() && controlPath[0] != '/')
348341
rulePath += '/';
349342

350-
rulePath += child;
343+
rulePath += controlPath;
351344

352345
// Check the read condition exists or matches
353346
if (readCondition.length() > 0)
@@ -388,12 +381,18 @@ bool mofifyRules(const String &parentPath, const String &child, const String &re
388381
else
389382
printError(aClient.lastError().code(), aClient.lastError().message());
390383
}
384+
else
385+
{
386+
Serial.println("The rules exist, nothing to change");
387+
}
391388

392389
currentRules.clear();
393390
return aClient.lastError().code() == 0;
394391
}
395392
else
396393
printError(aClient.lastError().code(), aClient.lastError().message());
397394

395+
Serial.println("-----------------------------------");
396+
398397
return false;
399398
}

‎library.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "FirebaseClient",
3-
"version": "1.5.10",
3+
"version": "1.5.11",
44
"keywords": "communication, REST, esp32, esp8266, arduino",
55
"description": "Async Firebase Client library for Arduino.",
66
"repository": {

‎library.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name=FirebaseClient
22

3-
version=1.5.10
3+
version=1.5.11
44

55
author=Mobizt
66

‎src/core/Core.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
#undef FIREBASE_CLIENT_VERSION
88
#endif
99

10-
#define FIREBASE_CLIENT_VERSION "1.5.10"
10+
#define FIREBASE_CLIENT_VERSION "1.5.11"
1111

1212
static void sys_idle()
1313
{

‎src/storage/DataOptions.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* 2025-02-08
2+
* 2025-02-13
33
*
44
* The MIT License (MIT)
55
* Copyright (c) 2025 K. Suwatchai (Mobizt)
@@ -58,12 +58,12 @@ namespace FirebaseStorage
5858
{
5959
URLUtil uut;
6060
this->bucketId = uut.getHost(bucketId);
61-
this->object = uut.getHost(object);
61+
this->object = object.length() && object[0] == '/' ? object.substring(1, object.length() - 1) : object;
6262
this->accessToken = accessToken;
6363
}
6464
String getObject() const { return object; }
6565
String getBucketId() const { return bucketId; }
66-
const char* getAccessToken() const { return accessToken.c_str(); }
66+
const char *getAccessToken() const { return accessToken.c_str(); }
6767
};
6868

6969
class DataOptions

0 commit comments

Comments
 (0)
Please sign in to comment.