Trying to block authentication if user is in the banned collection - javascript

I am building a chat app and I am trying to figure out the banning system. The idea if the user is in the banned collection becaused he used banned words, block authentication from his account. The problem is that for some reason it does execute the code but rather only does the signInWithRedirect() function. Take a look at my code:
const googleProvider = new GoogleAuthProvider();
const signInWithGoogle = async () => {
try {
const res = await signInWithRedirect(auth, googleProvider);
const user = res.user;
const q = query(collection(db, "banned"), where("uid", "==", user.uid));
const docs = await getDocs(q);
if (docs.exists()) {
//if exists ban the user
console.log('you cannot use this chat app , you are banned!)
Here is also the LoginPage.jsx
function LoginPage() {
const [user] = useAuthState(auth)
const navigate = useNavigate()
console.log(user)
return (
<div>
<div style={{'display': 'none'}}>
<Navbar />
</div>
<Welcome />
</div>
)
}
Here is also signOut
const navigate = useNavigate()
const signOutWithGoogle = () => {
signOut(auth)
navigate('/')
}
Here is firebase firestore
I tried this with promises but nothing happened , I used async , nothing happened

I would not implement such a "banning" system only based on front-end code. It would actually be quite easy for a malicious end-user to bypass your check based on a standard query to a collection.
I would use a Firebase Security Rule to enforce the banishment: Security Rules stand between your data and malicious users and are executed/checked in the back-end. To be complete, with this approach the user will still be authenticated and signed-in but will not be able to interact with the Firebase back-end services like Firestore or Cloud Storage.
Concretely you could as follows:
Write a security rule based on a specific collection in which you create a document per banned user with the user ID as document ID. Then you can use the exists() method to check if the user is banned or not.
Use a Cloud Function to ban (and maybe "un-ban") a user. Again, with Cloud Function the code is executed in the back-end and you therefore avoid the possibility that a malicious user writes a code that could "un-ban" him.

Related

Importing User Data from filtered Array (VUE3 + Quasar + Firebase)

I am importing the data from the currently signed in user in order to manage the entire user profile page and all the associated actions.
On one hand I have the auth.currentUser and on the other I have the USERS collection in the db which stores all the additional data related to that particular user.
Now, my question concerns optimization. What would be the ideal way to get this user's data? Currently I am getting the entire users collection and filtering to get the one that matched the uid from the route params, yet I was told that loading the entire users collection and filtering the one I want to display was less than ideal, that I should rather create a function to get a specific user by a property such as name or id. This is what confuses me, is that not essentially what I am doing by filtering the users collection? How else would it be best to get that user's info? By creating this function in the Store and not in the component itself?
Currently it's looking like this:
UserPage.vue
const storeUsers = useUserStore();
const users = storeUsers.users;
const route = useRoute();
const id = route.params.id;
const userData = computed(() => {
return users.find((u) => u.uid == id);
});
Any way to optimize this would be appreciated.
*Adding a screenshot of the Firestore console (data model):
Your code is loading every document from the users collection into your application code, and then choosing there which single document you are actually interested in. Since you pay for every document read from the database, and you (and your users) pay for all bandwidth that is used, this is wasteful - especially as you start adding more users to the collection.
Instead you should use a query to read only the document(s) you are interested in from the database into your application code. Read the documentation for examples for all supported SDK versions.
finally solved it using a query as suggested. I am triggering the getUserInfo action whenever a user signs in and then assigning it to a pinia state called currentUserData:
AUTH STORE
async getUsers() {
onSnapshot(userCollectionRef, (querySnapshot) => {
let users = [];
querySnapshot.forEach((doc) => {
let user = {
did: doc.id,
...doc.data(),
};
this.users.push(user);
});
});
},
getUserInfo(userCredential) {
const q = query(
userCollectionRef,
where("uid", "==", userCredential.user.uid)
);
onSnapshot(q, (snapshot) => {
let currentUserData = [];
snapshot.docs.forEach((doc) => {
currentUserData.push({ ...doc.data(), id: doc.id });
});
this.currentUserData = currentUserData;
});
}

Limit pages to certain user type Nuxt & Firebase Firestore (Role-Based Authorization)

need some advice here.
My Nuxt & Firebase/Firestore web app will have 3 different type of users:
subcontractor
contractor
worker
First, I want my users, whenever they login, they will log into page related to their user type.
e.g: subcontractor login push to /subcontractor, contractor login push to /contractor etc etc.
I also want the user can only see pages related to their types. (user A only see /A & /Atwo, user B can only see /B & /Btwo, user C, can only see /C & /Ctwo etc etc..)
I want to avoid using cloud functions if can, as from what I understand, you cannot deploy your app in the free plan if your app has cloud functions in it.
Anyway, is below the right way to do it?
Create in firestore, Users document that contains details of user type,
e.g: "userType: subcontractor"
In the middleware, do the logic, based on user type.
(in my case, I need to have 3 diff middleware js file (isSubcontractor.js, isContractor.js, isWorker.js)
add middleware: "the-middleware file", inside my page
If its correct, how to do step 1 & 2?
Is there any articles or real-life application source code that explain briefly what I wanted?
Beginner here. Already gone thru here and there around the internet but can't quite find the answer that I wanted :(
Custom Claims are definitely an option but that would require Cloud functions or a server. Yes, you can store user type in their Firestore document and check it before the page renders or whenever required. However, you must make sure only authorized users can change their role.
The flow would be as simple as:
User logs in
Reading their role from Firestore document
Redirecting to relevant page
import { getAuth, signInWithEmailAndPassword } from "firebase/auth";
import { getFirestore, doc, getDoc } from "firebase/firestore";
const auth = getAuth();
const firestore = getFirestore();
const login = async () => {
const { user } = await signInWithEmailAndPassword(auth, email, password);
// Reading user document
const docRef = doc(firestore, "users", user.uid);
const docSnap = await getDoc(docRef);
const { userType } = docSnap.data()
switch (userType) {
case 'contractor':
// redirect to /contractor
break;
case 'sub-contractor':
// redirect to /sub-contractor
break;
default:
// redirect to default page
break;
}
}
I also want the user can only see pages related to their types.
You can follow them same method in a server side middleware. First read userType and then check if user is authorized to visit the page. If not, redirect to any other page.
Best part of using Custom Claims is that you can read them in security rules of Realtime Database, Firestore and Storage as well. If you store user type in Firestore you cannot read that in security rules of any other Firebase service. Using Firestore also incurs additional charge for reading user's role every time. You need a Cloud function to set the custom claim only and not read the claim every time.

How to delete user with Vue.js Firebase UID

I am attempting to implement a function in my Vue.js Firebase app that deletes/removes users by UID. The app is set up to enable registration of users in Firebase authentication via email and password. Once logged in, the user should be able to click delete in order to remove his/her email and password from Firebase authentication, as well as user data. So far I have the following for the delete function:
async deleteProfile () {
let ref = db.collection('users')
let user = await ref.where('user_id', '==',firebase.auth().currentUser.uid).get()
user.delete()
}
...but I am getting user.delete() is not a function. How can I set up this function to delete the user in authentication and database? Thanks!
UPDATED FUNCTION
async deleteProfile () {
let ref = db.collection('users')
let user = await ref.where('user_id', '==', firebase.auth().currentUser.uid).get()
await user.ref.delete()
await firebase.auth().currentUser.delete()
}
In your code, user is a DocumentSnapshot type object. If you want to delete the document, you can use user.ref.delete(). It returns a promise, so you will need to await it.
Deleting a document will not also delete a user account in Firebase Authentication. If you want to delete the user account, you will have to use the Firebase Authentication API for that. firebase.auth().currentUser.delete().
try this
<button class="..." #click="deleteProfile(currentUser.uid)">Delete</button>
and
methods: {
async deleteProfile(dataId) {
fireDb.collection("yourCollection").doc(dataId).delete()
.then(() => {
alert('Deleted')
})
}
}
Building off Doug Stevenson's answer, this is the function that ultimately worked.
async deleteProfile (user) {
await db.collection("users").doc(user).delete()
await firebase.auth().currentUser.delete()
}
await db.collection("users").doc(user).delete() accepts "user" as an argument from the click event in the DOM, in order to target the doc of the specified user in the database (I don't know why I didn't think of that sooner!) await firebase.auth().currentUser.delete() removes currentUser from firebase authorization.

How can I check or verify that a user is signed in with AWS Cognito Javascript?

I am creating a React web app where the user sign in/up and other authentication related processes are being handled by AWS Cognito and the accompanying Javascript SDK.
My app has some 'public' routes/pages that everybody, signed in or not, can view, such as /documentation/ and /sign-in/. There also exist various private routes which you can only see when you are logged in, such as /my-documents/.
At the moment, I have a working sign in page, where a user is signed in with code very similar to use case #4 (Cognito Docs).
My question now is: as soon as a user goes to /my-documents/, how do I check whether the user is signed in and actually has the rights to see this page?
I am not using AWS Amplify for the authentication in my app. I only use the NPM package 'amazon-cognito-identity-js'.
This is the code I currently use to check if the session is valid, in other words if the user is successfully signed in. This however, seems like a cumbersome way to check such a simple status.
const isAuthenticated = () => {
const cognitoUser = userPool.getCurrentUser();
let isSessionValid = false;
if (cognitoUser) {
cognitoUser.getSession((err: Error, result: CognitoUserSession) => {
if (!err) {
isSessionValid = result.isValid();
}
});
}
return isSessionValid;
};
isSessionValid is returned before the callback in getSession is executed.

Getting id of the current user from Cloud Functions and Firebase

I am using google cloud functions to register push notifications through firebase. In my app, i have a notifications reference that changes for a current user whenever they get a new follower or like, etc. As of right now I am able to send the notification to the phone whenever that whole reference child changes
For example, if any single post is liked, then it will send a notification. What I need to do is observe the current user to only send the notification that single person.
Here is my JavaScript file
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendPushNotification = functions.database.ref('/notification/{id}').onWrite(event => {
const payload = {
notification: {
title: 'New message arrived',
body: 'come check it',
badge: '1',
sound: 'default',
}
};
return admin.database().ref('fcmToken').once('value').then(allToken => {
if (allToken.val()) {
const token = Object.keys(allToken.val());
return admin.messaging().sendToDevice(token, payload).then(response => {
});
}
});
});
I would like to replace this line:
functions.database.ref('/notification/{id}').onWrite(event => {
With this:
functions.database.ref('/notification/{id}').(The current user ID).onWrite(event => {
How do I get the current users id?
You seem very new to JavaScript (calling it JSON is sort-of a give-away for that). Cloud Functions for Firebase is not the best way to learn JavaScript. I recommend first reading the Firebase documentation for Web developers and/or taking the Firebase codelab for Web developer. They cover many basic JavaScript, Web and Firebase interactions. After those you'll be much better equipped to write code for Cloud Functions too.
Now back to your question: there is no concept of a "current user" in Cloud Functions. Your JavaScript code runs on a server, and all users can trigger the code by writing to the database.
You can figure out what user triggered the function, but that too isn't what you want here. The user who triggered the notification is not the one who needs to receive the message. What you want instead is to read the user who is the target of the notification.
One way to do this is to read it from the database path that triggered the function. If you keep the notifications per user in the database like this:
user_notifications
$uid
notification1: ...
notification2: ...
You can trigger the Cloud Function like this:
exports.sendPushNotification = functions.database.ref('/user_notification/{uid}/{id}').onWrite(event => {
And then in the code of that function, get the UID of the user with:
var uid = event.params.uid;
For Swift 3.0 - 4.0
You can do this:
import Firebase
import FirebaseAuth
class YourClass {
let user = Auth.auth().currentUser
let userID = user.uid
// user userID anywhere
}

Categories