How to pass uid as a parameter in firebase? React+Firebase - reactjs

I am using react and have logged in user using firebase auth and storing the uid app context.
Security rules:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read;
allow write: if
request.auth!=null;
}
}
}
I want to keep this security rules.
I want to make request with uid. How do i do that?
This way gives error.
await db.collection('users').doc(uuid).set({name:name});
Uncaught (in promise) FirebaseError: Missing or insufficient permissions.
How do i pass uid as parameter to each request while writing to the database?

It's not clear how you initialize uuid right now, but it should be:
firebase.auth().onAuthStateChanged((user) => {
if (user) {
var uuid = user.uid;
await db.collection('users').doc(uuid).set({name:name});
} else {
// User is signed out
// ...
}
});
This snippet comes pretty directly from the Firebase documentation on getting the current user.

Related

Firebase Storage "Permission denied" error

When I try to read my Firebase Storage data I'm getting the following error:
Uncaught (in promise) FirebaseError: Firebase Storage: An unknown error occurred, please check the error payload for server response. (storage/unknown)
{
"error": {
"code": 400,
"message": "Permission denied. Please enable Firebase Storage for your bucket by visiting the Storage tab in the Firebase Console and ensure that you have sufficient permission to properly provision resources."
}
}
But my rules are set to public:
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write;
}
}
}
What am I missing? Here's my code:
export const getAll = async () => {
let list: Photo[] = [];
const imagesFolder = ref(storage, "images");
const photoList = await listAll(imagesFolder);
for(let i in photoList.items) {
let photoUrl = await getDownloadURL(photoList.items[i]);
list.push({
name: photoList.items[i].name,
url: photoUrl
});
}
return list;
}
Following the steps in this post fixed my issue:
This is due to a missing permission:
firebase-storage#system.gserviceaccount.com
Go to https://console.cloud.google.com
Select your project in the top blue bar
Scroll down the left menu and select "Cloud Storage"
Select all your buckets then click "ADD PRINCIPAL" on the right
Add "firebase-storage#system.gserviceaccount.com" and "Storage
Admin" as a role
Save it
https://newbedev.com/firebase-storage-security-rules-400-error-issue-permission-denied-could-not-access-bucket-xxxxx-appspot-com
Before you setting for storage admin, make sure you have activate your google cloud platform. Because it's can be the first cause, if you use firebase storage and you never use google cloud platform before

Uncaught Error in snapshot listener: FirebaseError: Missing or insufficient permissions for chatRooms

I have chatrooms stored in Cloud Firestore that need to be secured and I'm having a difficult time doing so. My state in React looks as such:
export class Messages extends React.Component {
constructor(props) {
super(props);
this.boardID = this.props.settings.id;
this.mainChatRef = database
.collection("boards")
.doc(boardID)
.collection("chats")
.doc("MAIN")
.collection("messages");
this.chatRoomsRef = database
.collection("boards")
.doc(boardID)
.collection("chats");
}
My query in react looks like:
latestMessages = (messageSnapshot) => {
const message = [];
messageSnapshot.forEach((doc) => {
const { text, createdAt, uid } = doc.data();
message.push({
key: doc.id,
text,
createdAt,
uid,
});
});
this.setState({
dataSource: message,
});
}
queryRooms = async () => {
const recentQuery = await this.chatRoomsRef
.where("uidConcat", "in", [
this.props.user.uid + this.state.value.objectID,
this.state.value.objectID + this.props.user.uid,
])
.get();
for (const qSnap of recentQuery.docs) {
const messagesRef = this.chatRoomsRef
.doc(qSnap.id)
.collection("messages")
.orderBy("createdAt")
.limitToLast(30);
messagesRef.onSnapshot(this.latestMessages);
}
}
My database structure:
boards(collection)
{boardId}
chats (collection)
MAIN
{chatId_1}
{chatId_2}
uidArray (has only two UIDs since it's for private chat)
uidConcat: user1_uid+user2_uid
messages(collection)
{message1}
createdAt
text
uid_creator
uidArray (has UID of user1 and user2)
I tried securing my boards as such:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /boards/{boardId} {
allow read, write: if request.time < timestamp.data(2050, 5, 1);
match /chats/MAIN/messages/{messagesId=**} {
allow read, create: if request.auth.uid !=null;
}
match /chats/{chatId} {
allow read, write: if request.auth.uid !=null;
match /messages/{messagesId=**} {
allow read: if (request.auth.uid in get(/databases/{database}/documents/boards/
{boardId}/chats/{chatId}/messages/{messageId}).data.uidArray)
&& request.query.limit <= 30 && request.query.orderBy.createdAt == 'ASC';
allow write: if request.auth.uid != null;
}
}
}
}
}
I wish to have anyone that's authenticated to always have access to the boards MAIN chat and the way I have it written it works. For private rooms I keep getting an error. I've read the documents and I know that Security rules are not filters which is why I added a bunch of AND statements in an attempt to closely resemble my securities to my written code query in React yet I still keep getting Uncaught Errors in snapshot listener: FirebaseError: Missing or insufficient permissions. I am currently writing my rules to secure at the document level within the messages collection but Ideally I'd like to secure at the document level in the chat colection and check if my request.auth.uid is in the document field uidArray as so :
match /chats/{chatId=**} {
allow read, write if request.auth.uid in resource.data.uidArray
}
I imagine securing the documents in the chat collection would be more secure but any method that secures messages is more than appreciated.
The problem is that you're attempting to do a dynamic lookup in your rule based on each row of the data in this line: get(/databases/{database}/documents/boards/{boardId}/chats/{chatId}/messages/{messageId}).data.uidArray)
The critical point to understand here is that rules do not look at the actual data when perform queries. Get operations are a bit different because there's exactly one record to fetch, but for queries, it only examines the query to ensure it cannot fetch data that doesn't match your rule; it never actually loads data to examine. This is covered in docs here and there's a good video overviewing this here. A deeper dive is here.
Role based access is a complex topic and probably not easy to answer in a Stack Overflow given how broad the solutions would be, and how specific they are to your use case. But a naïve alternative would be to list the members in /chats/{chatId} and use a rule like this:
match /chats/{chatId} {
// scoped to chats/{chatId} doc
function isChatMember(uid) {
// assumes this document contains an array of
// uids allowed to read the messages subcollection
return uid in resource.data.members;
}
match /messages/{messagesId=**} {
allow read: if isChatMember(request.auth.uid)
}
}

Auth0 Email Whitelist Rule blocks users from Login is too strict

I have an auth0 rule which only allows users with my domain like #mybusiness.com to login through auth0 hook in reactjs application.
However, if a user accidentally tries to login with another email domain they don't get in - this is good - but then they cannot even retry with another email as they are 'Unauthorized'. This is bad.
// Access should only be granted to verified users.
if (!user.email || !user.email_verified) {
return callback(new UnauthorizedError('Access denied.'));
//
}
const whitelist = ['mybusiness.com']; //authorized domains
const userHasAccess = whitelist.some(function (domain) {
const emailSplit = user.email.split('#');
return emailSplit[emailSplit.length - 1].toLowerCase() === domain;
});
if (!userHasAccess) {
return callback(new UnauthorizedError('Access denied.'));
//
}
return callback(null, user, context);
}
I have to go in and delete the user from Auth0 to allow them to try again. My thoughts are to throw a different error but I have tried a few punts but couldn't find any documentation for Auth0 rules. Note* this is a auth0 predefined rule not a custom rule.

How to retrieve Azure Key Vault in React JS

I have created some setting in Azure and I need fetch some secret keys from there in react js
const KeyVault = require('azure-keyvault');
const msRestAzure = require('ms-rest-azure');
var KEY_VAULT_URI = "https://mydomain.com.vault.azure.net/";
msRestAzure.loginWithAppServiceMSI({resource: 'https://vault.azure.net', msiEndpoint: 'https://vault.azure.net', msiSecret: '69418689F1E342DD946CB82994CDA3CB', msiApiVersion: '' }).then((credentials) => {
const keyVaultClient = new KeyVault.KeyVaultClient(credentials);
var data = keyVaultClient.getSecret(KEY_VAULT_URI, 'My_Secret_Key');
console.log(data);
});
I'm getting some issue net::ERR_NAME_NOT_RESOLVED, I think I'm missing something. Could anyone please suggest that how to retrieve that secret keys from Azure in React Js
Using the loginWithAppServiceMSI() method from ms-rest-azure will autodetect if you're on a WebApp and get the token from the MSI endpoint. So you must host your code on Azure webapp. Refer to this article for more details.
function getKeyVaultCredentials(){
return msRestAzure.loginWithAppServiceMSI({resource: 'https://vault.azure.net'});
}
function getKeyVaultSecret(credentials) {
let keyVaultClient = new KeyVault.KeyVaultClient(credentials);
return keyVaultClient.getSecret(KEY_VAULT_URI, 'secret', "");
}
getKeyVaultCredentials().then(
getKeyVaultSecret
).then(function (secret){
console.log(`Your secret value is: ${secret.value}.`);
}).catch(function (err) {
throw (err);
});
If you don't have to use Managed Service Identity (MSI), you can use msRestAzure.loginWithServicePrincipalSecret(clientId, secret, domain) to get the credentials.
function getKeyVaultCredentials(){
return msRestAzure.loginWithServicePrincipalSecret(clientId, secret, domain);
}

Error: permission_denied at /categories: Client doesn't have permission to access the desired data

I have an assignment given by some recruiter and here I need to build an e-commerce site using react redux, and firebase.
The front end part is done but not able to get the data from firebase.
here is my rules Tab content how can I modify it.
this.props.firebase.categories().on('value', snapshot => {
// Not coming here.
console.log(snapshot, snapshot.val)
}, (error) => {
// Error shows here
console.log(error);
});
// Content of Rules tab
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if true;
}
}
}
Followed this tutorial:
https://www.robinwieruch.de/complete-firebase-authentication-react-tutorial/#react-application-setup
Set read and write permissions to true in rules (firebase).

Resources