So I'm following a Savvy Apps tutorial in order to learn Vue.js. This tutorial uses Firebase with Firestore. Since Firestore is in Beta (as the tutorial says), changes might happen - and I think that might be the case here.
In any case, I'm trying to sign up a new user. I fill out the form and click 'Sign up' and I get this error message:
Error: Function CollectionReference.doc() requires its first argument to be of type string, but it was: undefined
But looking in Firebase, I see that the user has been created. So why do I get this error message? What is the first argument?
The code for signup looks like this:
signup() {
this.performingRequest = true;
fb.auth.createUserWithEmailAndPassword(this.signupForm.email, this.signupForm.password).then(user => {
this.$store.commit('setCurrentUser', user);
// create user obj
fb.usersCollection.doc(user.uid).set({
name: this.signupForm.name,
title: this.signupForm.title
}).then(() => {
this.$store.dispatch('fetchUserProfile');
this.performingRequest = false;
this.$router.push('/dashboard')
}).catch(err => {
console.log(err);
this.performingRequest = false;
this.errorMsg = err.message
})
}).catch(err => {
console.log(err);
this.performingRequest = false;
this.errorMsg = err.message
})
},
Let me know if you need more code - this is the first time I'm testing Vue.js.
createUserWithEmailAndPassword() returns a Promise containing a UserCredential. UserCredential has a property user for the firebase.User object.
You need to make the appropriate changes to your code to correctly access the UID:
signup() {
this.performingRequest = true;
fb.auth.createUserWithEmailAndPassword(this.signupForm.email, this.signupForm.password)
.then(credential=> { // CHANGED
this.$store.commit('setCurrentUser', credential.user); // CHANGED
// create user obj
fb.usersCollection.doc(credential.user.uid).set({ //CHANGED
name: this.signupForm.name,
title: this.signupForm.title
}).then(() => {
this.$store.dispatch('fetchUserProfile');
this.performingRequest = false;
this.$router.push('/dashboard')
}).catch(err => {
console.log(err);
this.performingRequest = false;
this.errorMsg = err.message
})
}).catch(err => {
console.log(err);
this.performingRequest = false;
this.errorMsg = err.message
})
},
Related
Node.js CODE
exports.user = async (req, res) => {
try {
const { wallet } = req.body;
if (!wallet) {
res.status(400).json({ error: "Not logged in" });
return;
} else {
user = User.findone(wallet);
// if user is not found then create a new user and mark as loggged In
if (!user) {
User.create({
user: wallet,
});
}
// if user found then create a session token and mark as logged
in
res.send({
user: wallet,
});
}
} catch (error) {
console.log(`ERROR::`, error);
}
};
REACTJs CODE
// post call/update
const axiosCall = async () => {
// core login will give a unique username by fulling a transcation
// core.login i dont have any control
const userAccount = await core.login();
try {
const res = await Axios.post(`${API}/user`, userAccount, dataToken);
setData({
...data,
error: "",
success: res.data.message,
});
} catch (error) {
setData({
...data,
error: error.response.data.error,
});
}
};
Now here the problem occurs when some one could modify userAccount in the front-end or someone could send a body with wallet: anything to my route localhost:3000/api/user
There is no option for me to check if some actually used core.login(); to get the wallet address.
So is there any solution?
I was thinking to allow only my server IP or localhost to hit the route localhost:3000/api/user and is that even possible?
Also there is another issue anyone could modify userAccount in front-end.
I am using NodeJS, Express and plain vanilla javascript/html. Not React or anything else.
With firebase I made it to when the user registers, they will automatically be called a customer (on the server-side). As shown:
server.js
app.post('/register', (req,res) => {
let {first_name, last_name, email, uid} = req.body;
db.collection('users').doc(uid).set(req.body)
.then(data => {
res.json({
uid: req.body.uid,
first_name: req.body.first_name,
last_name: req.body.last_name,
email: req.body.email,
seller: req.body.seller
})
})
admin.auth()
.setCustomUserClaims(uid, {
type: "customer",
})
.then(() => console.log('done'))
})
But now, I would like to make this route to where it will redirect if the type is a customer.
if(idToken.claim.type === 'customer') {redirect('/') }
app.get('/seller', (req,res) => {
res.sendFile(path.join(staticPath, "seller.html"));
})
So I thought, what if I were to get the Token from the user and the type as soon as they log in, and send it back to the client. This will work.
login.js
firebase.auth().currentUser.getIdTokenResult()
.then((idTokenResult) => {
fetch('/getMyClaims', {
method: 'post',
headers: {'Content-Type':'application/json'},
body: JSON.stringify({uid: user.uid,
idToken: idTokenResult.claims.type}),
})
.then(() => res.json)
.catch(err => console.log(err));
});
and now my server.js now includes:
app.post('/getMyClaims', async(req,res) => {
let {uid,idToken} = req.body;
admin.auth()
.getUser(uid)
.then((userRecord) => console.log(userRecord))
})
and this is where I get stuck, because I am trying to find out how can I call the results of '/getMyClaims' to redirect a user, if they are a customer and are trying to access the '/seller' URL.
I did read the documents as given https://firebase.google.com/docs/auth/admin/custom-claims, but it does not really show how to re-route if claim has a specific type in the backend.
I've figured things out after hours of this!
server.js
var block;
var blockware = (req,res,next) => {
if(block == true || block == undefined){
console.log("deny access", block);
return res.sendStatus(401);
}
console.log("allow",block);
next();
}
app.post('/getMyClaims', async(req,res) => {
let {uid,idToken} = req.body;
if(idToken === 'customer'){
block = true;
} else if(idToken === 'admin'){
block = false;
} else {
block = true;
}
admin.auth()
.getUser(uid)
.then((userRecord) => console.log(userRecord))
})
app.get(['/seller', '/products', '/'], blockware, (req,res) => {
res.sendFile(path.join(staticPath, ""));
})
So now if user has a customer type claim then they are blocked from accessing seller. Otherwise, admin can access seller.
Even when user is logged out since it is automatically set to true, everyone will be blocked from it.
referenced this: express.js - single routing handler for multiple routes in a single line
Here i am trying to register a user with same flat number. But restrict the 2 user can register with same flat number.Here what i wanted to do is check whether any 2 user has register with same flat or not,If yes then no other member will get register and prompt a message and if no user or only 1 user has register then user can successfully get register with the system. my if condition alert value of len but when i put my code inside that condition not alert i got.
here is my code
registerUser(phoneNumber: number) {
alert('flat' + this.flatn.value);
var q = firebase.database().ref('users').orderByChild('flatno').equalTo(this.flatn.value);
q.once('value', (snapshots: any) => {
// alert(JSON.stringify(snapshots.val()));
this.len = snapshots.numChildren();
alert('len ='+this.len);
if(this.len < 2){
this.alert('success');
// i wanted to register user only if this condition gets true. but my code is not being perform as i want which is written after if condition.
}else{
//this.alert('success');
this.alert('More than 2 users are not allowed to register with same flat');
// flatno does not yet exist, go ahead and add new user
}
this.fire.auth
.createUserWithEmailAndPassword(this.email.value, this.password.value)
.then(data => {
let currentUserUid = this.fire.auth.currentUser.uid;
this.uniqueDeviceID.get()
.then((uDid: any) => this.uDid = uDid)
.catch((error: any) => alert('err' + error));
alert(this.uDid);
firebase.database().ref('users/' + currentUserUid).set({
ID: currentUserUid,
email: this.email.value,
password: this.password.value,
first_name: this.fname.value,
last_name: this.lname.value,
contact_no: this.phone.value,
flatno: this.flatn.value,
wing: this.wing.value,
parking_slot: this.vehicle.value,
familyMember: this.familyMember.value,
username: this.user.value,
device_id: this.uDid
});
this.fdb.list("/users_device/").push({
device_id: this.uDid,
Uid: currentUserUid
});
console.log("got data ", data);
//this.alert(data);
this.alert("Registered!");
data.sendEmailVerification().then(
function () {
this.alert("Email Sent Please check your mailbox!");
},
function (error) {
alert("error!");
}
);
this.navCtrl.push(LoginPage);
if (this.authForm.valid) {
let loader = this.loadingCtrl.create({
content: 'Registering...',
dismissOnPageChange: true
});
loader.present();
this.navCtrl.push(LoginPage);
}
})
.catch(error => {
console.log("got an error ", error);
this.alert(error.message);
});
});
}
I do not think that len exists in your scope. check that this property exists and not undefined this.len
I have this rule, it passed the simulated test but the client got the error "permission denied" after successfully authenticated using google. The partial rule below check for the uid object inside users object, if it doesn't exist, it is allowed to create an object
!(root.child('users').child(auth.uid).exists())
The whole rules json is below:
{
"rules":{
".read":"root.child('users').child(auth.uid).child('roles/admin').val()===true || root.child('users').child(auth.id).child('id').val()===auth.uid",
".write":"!(root.child('users').child(auth.uid).exists()) || root.child('users').child(auth.uid).child('roles/admin').val()===true || root.child('users').child(auth.id).child('id').val()===auth.uid",
}
}
The Angular code:
#Effect() loginGetUserInfo$ = this.actions$.pipe(
ofType(AuthActionTypes.AUTH_LOGIN_GET_USER_INFO),
map((action: AuthLoginGetUserInfo) => action.user),
exhaustMap((googleUser: User) => {
const ref = this.db.object('users/' + googleUser.uid);
debugger;
return ref.valueChanges().pipe(
map((user: User) => {
debugger;
if (!user) {
console.log("Is a new user:", googleUser);
//ref.set(googleUser);
ref.update(googleUser)
return new AuthLoginSuccessful(googleUser)
}
return new AuthLoginSuccessful(user)
}),
catchError(error => {debugger; return of(new AuthLoginFailure(error)) })
)
})
);
admin create new user from secondary app helped me.
FirebaseApp secondary = Firebase.app('Secondary');
final secondaryAth = FirebaseAuth.instanceFor(app: secondary);
userCreds = await secondaryAth.createUserWithEmailAndPassword(
email: email, password: password);
This is a real niche question regarding Twitter OAuth with passport.js ()
I have a controller which updates the user's avatar using their Twitter "avatar":
const signInViaTwitter = (twitterProfile) => {
return new Promise((resolve, reject) => {
console.log(twitterProfile);
// find if user exist on in
User.findOne({ username: twitterProfile.username }, (error, user) => {
if (error) { console.log(error); reject(error); }
else {
// user existed on db
if (user) {
// update the user with latest git profile info
user.name = twitterProfile.displayName;
user.username = twitterProfile.username;
user.avatarUrl = twitterProfile.photos.value;
user.email = '';
// save the info and resolve the user doc
user.save((error) => {
if (error) { console.log(error); reject(error); }
else { resolve(user); }
});
}
// user doesn't exists on db
else {
// check if it is the first user (Adam/Eve) :-p
// assign him/her as the admin
User.count({}, (err, count) => {
console.log('usercount: ' + count);
let assignAdmin = false;
if (count === 0) assignAdmin = true;
// create a new user
const newUser = new User({
name: twitterProfile.displayName,
username: twitterProfile.username,
avatarUrl: twitterProfile.photos.value,
email: '',
role: assignAdmin ? 'admin' : 'user',
});
// save the user and resolve the user doc
newUser.save((error) => {
if (error) { console.log(error); reject(error); }
else { resolve(newUser); }
});
});
}
}
});
});
};
The authentication of the user works - but for some reason, the avatar won't show...here is the following console output:
Refused to load the image 'https://api.twitter.com/favicon.ico'
because it violates the following Content Security Policy directive:
"img-src https://abs.twimg.com https://*.twimg.com
https://pbs.twimg.com data:".
Does anyone know what this means? I'm thinking it's probably due to being in development mode - that is, http://localhost:8080/ ... and it won't accept https?? Or won't pass it back?
UPDATE: ^I think the above error is unrelated to the image not being display...
A little look at the html source gives:
<img class="styles__userAvatar___2x2U9" src="{unknown}" alt="Wind Up Lord Vexxos Avatar">
So it's obviously passing in an unknown variable for the src - rather than the user's display avatar...
So, for me it looks like the offending line is:
user.avatarUrl = twitterProfile.photos.value;
What should I be setting this to?
Just a thought, isn't twitterProfile.photos an array? probably you should try accessing twitterProfile.photos[0].value