My question probably not limited to firebase database only, but my problem happened while i working on the Angular Project that using Firebase Database so i will tag Firebase & Angular as well.
According to the Firebase Real Time Database documentation, most of the ThenableReference is returning a Promise.
When i write a basic function like pushing new object to DB or updating an existing object in DB, it will return me a Promise, so i can use then to perform next action after done the action with DB.
When there is an error (Permission Denied for example), i can make it display on the screen like this:
But my problem is, I can't figure out how to write the error into DB to log it down.
Below is my code:
this.clientService.createClient(this.client).then(data=>{ //when successfully Push object to DB
this.loggerService.log('success','createClient', this.client, {id:data['key'],msg:'Successfully Create the Client'}, 'add-client') //Log the result into DB
this.router.navigate(['search-results',data.key,'client-details']) //route user to another page
this.toastrService.success('','Successfully Create the Client') //display a successful Pop Up message
},error=>{
console.log(error) //this is working
let msg = error.toString()
this.loggerService.log('error','createClient', this.client, msg, 'add-client') //this is not working
this.toastrService.error(error,'Failed to create the Client') //this is working like the attached photo
});
Below is my loggerService.log code:
log(status,action,req,res:Object,site){
let object = {
dtcreate: Date.now(),
uid:this.currentUser.uid,
userEmail:this.currentUser.email,
action:action,
req:req,
res:res,
site:site,
status:status
}
return this.logRef.push(object)
}
Edited:
Below is the error for the console.log(error), this is what i wish to log into my DB (Error: PERMISSION_DENIED: Permission denied).
Error: PERMISSION_DENIED: Permission denied
at vendor.js:88796
at exceptionGuard (vendor.js:76410)
at Repo.push../node_modules/#firebase/database/dist/index.cjs.js.Repo.callOnCompleteCallback (vendor.js:88787)
at vendor.js:88564
at vendor.js:87739
at PersistentConnection.push../node_modules/#firebase/database/dist/index.cjs.js.PersistentConnection.onDataMessage_ (vendor.js:87772)
at Connection.push../node_modules/#firebase/database/dist/index.cjs.js.Connection.onDataMessage_ (vendor.js:87057)
at Connection.push../node_modules/#firebase/database/dist/index.cjs.js.Connection.onPrimaryMessageReceived_ (vendor.js:87051)
at WebSocketConnection.onMessage (vendor.js:86952)
at WebSocketConnection.push../node_modules/#firebase/database/dist/index.cjs.js.WebSocketConnection.appendFrame_ (vendor.js:86557)
Thanks in advance!
Related
I am writing an app, where I want to give the user possibility to change their password. So I have a simple UpdatePassword.js page, where I invoke Firebase Authentication .updatePassword(password) method. As explained in the docs, this is a sensitive operation, and as such, the user needs to authenticate (if they haven't authenticated recently), in order to change their password to a new one.
This is my method:
const update = async () => {
const user = await firebase.auth().currentUser;
await user
.updatePassword(password)
.then(() => {
setUpdated(true);
})
.catch((error) => {
//I want to handle this specific error but I don't know how
if (
error.message ===
"This operation is sensitive and requires recent authentication. Log in again before retrying this request."
) {
console.log("should display a modal for user to authenticate again");
}
console.log("error while updating pass: ", error);
setSaving(false);
});
};
As you can see from my console.logs, in the case where the user needs to authenticate again, I want to display a modal, where they will sign in with their credentials again. This is not a problem and is easy to do. However, my question is, how do I catch this specific type of error where the user needs to authenticate? As per my console.logs, the way I have implemented it right now, I am just comparing the error message which I receive from Firebase Authentication, which is really not the right way to do. What if Firebase Auth change the error message to something else? Is there something like an error code which I can compare to the error thrown, and handle the exception by error code or something more safe than just a string message?
As you will see in the doc, the error that is thrown in this case (i.e. "if the user's last sign-in time does not meet the security threshold") has an auth/requires-recent-login error code.
So:
//...
.catch((error) => {
if (error.code === 'auth/requires-recent-login') {
// Display the modal
} else {
// ...
I'm using firebase-functions/lib/logger to log client-side firebase/firestore activity like
const { log, error } = require("firebase-functions/lib/logger");
export const addData = async (userId, dataId) => {
try {
const collectionRef = firestore
.collection("docs")
await collectionRef.add({
dataId,
});
log(`Data added`, { userId, dataId });
} catch (err) {
error(`Unable to add new data`, { userId, dataId });
throw new Error(err);
}
};
When I run this on my local, the log shows up in my browser console. Will this happen on non-local environments, ie for real users? Will these logs also show up automatically in Stackdriver, or are they stuck on the client side? I want to be able to view the logs either in Stackdriver or Firebase console but have them not show up in the browser for real users. How should I accomplish this?
Messages logged in Cloud Functions will not show up in the client app at all (that would probably be a security hole for your app). They will show up in the Cloud Functions console in the log tab, and in StackDriver.
Any messages logged in your app will not show up in any Google Cloud product. They are constrained to the device that generated them. If you want cloud logging, you'll need to implement some other solution. Cloud Functions does not support this - you will need to investigate other solutions or build something yourself.
I've built a Javascript web app using Firestore and Firebase. When logging the user out, I am getting console errors. The errors reference the firebase-database.js and firebase-firestore.js scripts, though, so I can't really tell what is happening:
[2020-05-22T12:32:58.436Z] #firebase/database: FIREBASE WARNING:
Exception was thrown by user callback.
Hr#https://www.gstatic.com/firebasejs/7.6.1/firebase-firestore.js:1:48219
firebase-database.js:1:11297
FirebaseError: Invalid document reference. Document references must
have an even number of segments, but user has 1
firebase-firestore.js:1:48219
This is my log out function:
$('.logout').on('click', function(){
firebase.auth().signOut()
.catch(function(error){
console.log(error.code);
console.log(error.message);
});
});
Then I have a listener for firebase.auth().onAuthStateChanged which triggers this:
firestoredb.collection('user').doc(uid).update({
status: false,
last_changed: firebase.firestore.FieldValue.serverTimestamp()
})
.then(function(){
uid='';
$('#screenname').html('');
window.location='https://www.example.com/your-account.asp?task=logout&afterlogin=%2Fv2';
})
.catch(function(error){
console.log(error.code);
console.log(error.message);
});
What might be my strategy for tracking down this error since the console logs are not that helpful? The error does not really affect the performance of the app, since the user is logged out anyway (and redirected via Javascript), however it bothers me that there is an error.
EDIT: I am wondering if the cloud script that is running could be the problem. That might explain why I cannot identify the line number and why the error message is so vague. Here is my cloud script, can this be modified so that a missing UID value would be ignored? This is basically the script provided by Google for combining Firebase and Firestore to maintain session state of the user.
const functions=require('firebase-functions');
const admin=require('firebase-admin');
admin.initializeApp();
const firestore=admin.firestore();
exports.onUserStatusChanged=functions.database.ref('user/{uid}').onUpdate(
async (change, context) => {
const eventStatus=change.after.val();
const userStatusFirestoreRef=firestore.doc(`user/${context.params.uid}`);
const statusSnapshot=await change.after.ref.once('value');
const status=statusSnapshot.val();
if (status.last_changed>eventStatus.last_changed){
return null;
}
eventStatus.last_changed=new Date(eventStatus.last_changed);
return userStatusFirestoreRef.update(eventStatus);
}
);
I am trying to create a function that, when a device is registered in the app, will attach this device uid to the uid of the signed-in user who registered the device (this is in another firestore collection that is automatically created when a user registers).
Here is my code:
exports.addDeviceToUser = functions.firestore.document('device-names/{device}').onUpdate((change, context) => {
const currentUser = admin.auth().currentUser;
const deviceName = context.params.device;
var usersRef = db.collection('users');
var queryRef = usersRef.where('uid', '==', currentUser.uid);
if (authVar.exists) {
return queryRef.update({sensors: deviceName}).then((writeResult => {
return console.log('Device attached');
}));
} else {return console.log('Device attachment failed, user not signed in');}
});
I am consistently getting this error: "TypeError: Cannot read property 'uid' of undefined." Obviously I am not able to access the auth information of the current user. Why?
The Admin SDK doesn't have a sense of current user. When you say admin.auth(), you're getting back an Auth object. As you can see from the API docs, there is no currentUser property on it. Only the Firebase client SDK has a sense of current user, because you use that to get the user logged in.
If you need the client app to tell Cloud Functions code work with the user's identity, you have to send it an ID token from the client, and verify it on the server. Then the server can know who the end user is, and perform actions on their behalf. Typically you do this with an HTTP type trigger. Callable functions transmit this data automatically between the client and server, but you can do it manually yourself using code that works like this sample.
Right now, Firestore triggers don't have immediate access to the end user that made a change in the database. However, if you use the Auth UID of the user as the key of the document, and protect that document with security rules, you can at least infer the UID of the user based on the changes they make to the document by pulling it out of the id of the document that changed.
Because, by design, Cloud Functions executes on the back end and do not hold any information on which user was authenticated when adding/modifying the data in the database.
When writing the data in the 'device-names/{device}' document (from your app), you could include an extra piece of data which is the uid of the current user.
I'm trying to save an user on the Parse User table using
user.save(null,{
success: function(savedUser){
alert("We saved parseID");
},
error: function(error){
alert('Error'+JSON.stringify(error));
}
})
Unfortunately the error is thrown which contains the object I'm trying to save:
{"username":"ffsdfsd","password":"gdfgfdd","createAt":2016-09-21T13:13:18.965Z", "updatedAt":"2016-09-21T13:13:18.965Z","ACL":{"*":{"read":true},"2FUmrere":{"read":true,"write":true}},"sessionToken":"fdgfdgdgdgdf","objectId":"3ffd3f"}
Any idea? Is it something related to the ACL setting (only read permission)?
if the user that you are trying to save is not the logged in user then this is an ACL issue. When a new user is being created in the database the default ACL is public read but the write permissions are granted only to the user.
If you still want to save new data on this user without changing the default ACL you need to create a cloud code function and in the cloud code function you need to write the following code:
user.save(null,{
sessionToken: request.user.get("sessionToken")
}).then(function(user){
// user saved
},function(error){
// error handling
});
please notice that in my code i sent the logged in user session token (this is required in parse-server) and also i use Promises which is the best practice.