Unable to set basic auth security rules to FIRESTORE - react-native

Im trying to set rules to Firestore allowing all user to read and write around if they're signed in.
I already have my Authentication working with Firebase, using email and password.
But the simplest auth rule I write, it just throw me an error.
Im trying to make Firestore work with this rule:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth.uid != null;
}
}
}
But when I try to write to Firestore I got this:
If I try the Function Helpers Approach:
service cloud.firestore {
//Function
function isSignedIn() {
return request.auth.uid != null;
//Also tried with "request.auth != null"
}
//Rules
match /databases/{database}/documents {
match /{document=**} {
allow read: if isSignedIn();
allow write: if isSignedIn();
//Also tried with "allow read, write: if isSignedIn();"
}
}
}
It also throw me the same error.
I also tried matching custom paths, like match /Restaurants/{RestaurantsId} ... but also didn’t work…
But if I remove everything and I use the following default rule:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write;
}
}
}
it does work…
I’ve followed Firestore Documentation, AngularFirebase Video Tutorial, looked at github and here to similar cases and I still cant make it work. I see everybody that has tried this got this working perfectly, but it does not with me :S.
––––UPDATE 1––––
Here is how Im calling the set method of Firestore:
When I press a “Save Button” I call this helper function:
saveMealHandler() {
const { mealImage, mealCategory, mealName, mealIngredients, mealPrice, mealOptions, mealExtras, user } = this.props;
const id = this.props.completeMenu.length;
const { navigation } = this.props;
this.props.saveMeal({
key: id,
name: mealName,
avatar: mealImage,
ingredients: mealIngredients,
price: mealPrice,
category: mealCategory,
options: mealOptions,
extras: mealExtras
}, user);
this.props.cleanAllInputs();
}
and this helper call’s the following action creator which writes on Firestore:
export const saveMeal = (newMeal, user) => {
const db = firebase.firestore();
const docRef = db.collection('Resto').doc(user);
return dispatch => {
docRef.set({
isWorking: 'JALAPEÑO!'
})
.then(() => {
console.log('Document successfully written!');
})
.catch((error) => {
console.error('Error writing document: ', error);
});
dispatch({ type: SAVE_NEW_MEAL_TO_MENU, payload: newMeal });
};
};
––––UPDATE 1––––
––––UPDATE 2––––
This is the function which capture the user and password and calls the action creator:
onButtonPress() {
const { email, password } = this.props;
console.log(email, password);
this.props.loginUser({ email, password });
}
This is the action creator im using for register and login in an user
export const loginUser = ({ email, password }) => {
return (dispatch) => {
dispatch({ type: LOGIN_USER_START });
firebase.auth().signInWithEmailAndPassword(email, password)
.then(user => userLoginSuccess(dispatch, user))
.catch(() => {
firebase.auth().createUserWithEmailAndPassword(email, password)
.then(user => userLoginSuccess(dispatch, user))
.catch(() => userLoginFail(dispatch));
});
};
};
//Helpers
const userLoginSuccess = (dispatch, user) => {
dispatch({ type: LOGIN_USER_SUCCESS, payload: user.uid });
};
const userLoginFail = (dispatch) => {
dispatch({ type: LOGIN_USER_FAIL });
};
And this is how I know this functions are working:
––––UPDATE 2––––
With all my attempts I think may be I missed to install something without knowing in or there is something wrong when I add the condition. But It this moment I just prefer to ask.
I also recorded a video so you can see the issue, here it is:
https://youtu.be/9fmWk7-HjZ4
Thanks to everyone.

i came across same problem
import all firebase cdn below
https://www.gstatic.com/firebasejs/6.4.0/firebase-app.js
https://www.gstatic.com/firebasejs/6.4.0/firebase-auth.js
https://www.gstatic.com/firebasejs/6.4.0/firebase-firestore.js

Related

Is it possible to update the userAttributes(email) in aws cognito using React-Native?

I have tried below lines to update the userEmail in aws cognito.
For update email, the updateAttributes is needed.
import {Auth} from 'aws-amplify';
let user = await Auth.currentAuthenticatedUser();
user.session = user.signInUserSession;
let userAttributes = await Auth.userAttributes(user);
let new = { Name: 'email', Value: emailAddress }
Auth.updateUserAttributes(user, new).then((res) => {
console.log("success", res);
}).catch(e => {
console.log("EEE", e);
});
But when I tried, I got this error:
{"code": "InvalidParameterException", "message": "user.Value: Attribute does not exist in the schema.
user.Name: Attribute does not exist in the schema.
", "name": "InvalidParameterException"}
You are almost there, the input should just be a normal key/value where the key is 'email' and the value is the emailadress.
let new = { email: emailAddress } // <-- change this line
Auth.updateUserAttributes(user, new).then((res) => {
console.log("success", res);
}).catch(e => {
console.log("EEE", e);
});
Normally when working with cognito with the aws-sdk you should use the syntax that you did, but it is diffrent with amplify.
This way you can edit more userAttributes at once. Take a look at det amplify docs for a more detailed look:
https://docs.amplify.aws/lib/auth/manageusers/q/platform/js/#managing-user-attributes

Bcrypt + Sequelize password not saving as hash in DB

Sequelize + Bcrypt not storing passwords in DB as hash
As the title says, whenever I attempt to store a user into my SQLite DB the console outputs the password as a hash but when I look into the DB with DBbrowser I can see the plaintext password.
Model
// const Promise = require('bluebird')
const bcrypt = require('bcrypt')
async function hashPassword (user, options) {
if (!user.changed('password')) {
return 0
}
const SALT_FACTOR = 8
await bcrypt.hash(user.password, SALT_FACTOR, (err, hash) => {
if (err) {
console.log(err)
}
// user.setDataValue('password', hash)
user.password = hash
console.log(user)
})
}
module.exports = (sequelize, DataTypes) => {
const User = sequelize.define('User', {
email: {
type: DataTypes.STRING,
unique: true
},
password: DataTypes.STRING
}, {
hooks: {
beforeSave: hashPassword,
beforeCreate: hashPassword
}
})
User.prototype.comparePassword = function (password) {
bcrypt.compare(password, this.password, function (res, err) {
if (res) {
console.log(res)
} else {
console.log(err)
}
})
return bcrypt.compare(password, this.password)
}
return User
}
Controllers
module.exports = {
async register (req, res) {
try {
const user = await User.create(req.body)
const userJson = user.toJSON()
res.send({
user: userJson,
token: jwtSignUser(userJson)
})
} catch (err) {
// e-mail already exists or such
res.status(400).send({
error: 'This email address is already in use'
})
}
},
async login (req, res) {
try {
// Grab user input
const { email, password } = req.body
const user = await User.findOne({
where: {
email: email
}
})
// Check to see if user is in db
if (!user) {
res.status(403).send({
error: 'the login information was incorrect / Not Found'
})
}
// Check to see if password is valid
const isPasswordValid = await user.comparePassword(password)
if (!isPasswordValid) {
return res.status(403).send({
error: 'The login information was incorrect'
})
}
// return user using toJSON()
const userJson = user.toJSON()
res.send({
user: userJson,
token: jwtSignUser(userJson)
})
} catch (e) {
res.status(500).send({ error: 'An error occured attempting to login' })
console.log(e)
}
}
}
To elaborate a little more, whenever I create a user, I receive the following:
{
"user": {
"id": 1,
"email": 'test#test.com",
"password": "$2b$08$SYYXU/GDSCFsp3MVeuqrduI0lOLHeeub7whXiaMMoVxO53YJry.1i",
"updatedAt": "2018-09-07T22:44:12.944Z",
"createdAt": "2018-09-07T22:44:12.944Z"
},
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiZW1haWwiOiJTVVBCUkhVQGxvbC5jb20iLCJwYXNzd29yZCI6IiQyYiQwOCRTWVlYVS9HRFNDRnNwM01WZXVxcmR1STBsT0xIZWV1Yjd3aFhpYU1Nb1Z4TzUzWUpyeS4xaSIsInVwZGF0ZWRBdCI6IjIwMTgtMDktMDdUMjI6NDQ6MTIuOTQ0WiIsImNyZWF0ZWRBdCI6IjIwMTgtMDktMDdUMjI6NDQ6MTIuOTQ0WiIsImlhdCI6MTUzNjM2MDI1MywiZXhwIjoxNTM2OTY1MDUzfQ.mDaeIikzUcV_AGTuklnLucx9mVyeScGpMym1y0kJnsg"
}
Which to me says the DB successfully hashed my password, and stored it. The overhanging issue for me with this is the fact that I believe it's causing the bcrypt.compare function to spit out 'false'. As always, any insight or help would be greatly appreciated!
I'm pretty sure that this answer is too late for you, but might help others landing on this same question.
The main issue I can see is how you are using the async/await pattern. Changing this:
async function hashPassword (user, options) {
if (!user.changed('password')) {
return 0
}
const SALT_FACTOR = 8
await bcrypt.hash(user.password, SALT_FACTOR, (err, hash) => {
if (err) {
console.log(err)
}
// user.setDataValue('password', hash)
user.password = hash
console.log(user)
})
}
to this, worked for me:
async function hashPassword(user, options) {
if (!user.changed("password")) {
return 0;
}
user.password = await bcrypt.hash(user.password, SALT_FACTOR);
}
Can you please try to add only one hook
hooks: {
beforeSave: hashPassword,
}
Because I think your password is getting hashed two times. as beforeSave and beforeCreate both hooks get executed.
Hope it helps

undefined jwt token react/express

I am implementing a JWT authentication on a login/registration system. When there is a successful login/registration I am setting a user token in localStorage.
Problem is when I check my localStorage the user key is present but the value is undefined. I think the issue might be in my axios post or in my express file but I can't quite figure it out.
// my action creator
export function login(user, history) {
return async (dispatch) => {
axios.post('/api/login', { user })
.then(res => {
dispatch({ type: AUTHENTICATED });
localStorage.setItem('user', res.data.token);
history.push('/');
})
.catch((error) => {
dispatch({
type: AUTHENTICATION_ERROR,
payload: 'Invalid email or password'
});
});
};
}
The data is reaching my api correctly. The item is being set but the value res.data.token is undefined.. Below is my express file
// login.js (/api/login)
router.post('/', function(req, res) {
var email = req.body.user.email;
var password = req.body.user.password;
// TODO: create db file and import connection
var connection = mysql.createConnection({
host: "localhost",
user: "root",
password: "",
database: "dbname",
port: 3307
});
connection.connect(function(err) {
if(err) {
console.log(err);
} else {
connection.query("SELECT ID, Password FROM Users WHERE Email = ?", [email], function(err, result) {
if(err) {
console.log('Could not find account');
res.send(err);
} else {
var id = result[0].ID;
bcrypt.compare(password, result[0].Password, function(err, result) {
if(result) {
console.log(id);
res.json({ id });
} else {
console.log('Incorrect password');
}
});
}
});
}
});
});
Since the res.data.token in my action creator is returning undefined does that mean the response in my express file ( res.json([id]) ) is just returning defined?
You are not sending the response properly.
res.json([id]); Its just sending the array of id. That's why res.data.token is undefined. as data does not contain an object.
Send proper object like:
res.json({id});

NuxtJs - Cannot read property 'headers' of undefined

I'm a newbie in NuxtJs. I'm trying to implement an external API Call with axios which I get token and store it on cookie. Everything works well in development. But when I try to run npm run generate it gives me errors that I don't know what to do.
When I delete nuxtSeverInit, npm run generate runs smoothly. And after some research, i think that nuxtServerInit that I'm using shouldn't be used. Can anyone please tell me how to make it work.
This is the first project in a new company, so I'm trying to prove myself. Please help me with it. Will you.
Click here for image that shows the error that appears after npm run generate
This is store/index.js file
import Vuex from 'vuex'
var cookieparser = require('cookieparser')
const createStore = () => {
return new Vuex.Store({
state: {
auth: null,
},
mutations: {
update (state, data) {
state.auth = data
}
},
actions: {
nuxtServerInit ({ commit }, { req }) {
let accessToken = null
if (req.headers.cookie) {
var parsed = cookieparser.parse(req.headers.cookie)
if(parsed){
accessToken = parsed.auth
}
}
commit('update', accessToken)
},
}
})
}
export default createStore
middleware/authenticated.js file
export default function ({ store, redirect }) {
// If the user is not authenticated
if (!store.state.auth) {
return redirect('/login')
}
}
middleware/notAuthenticated.js file
export default function ({ store, redirect }) {
// If the user is authenticated redirect to home page
if (store.state.auth) {
return redirect('/app/dashboard')
}
}
login.vue file
validateBeforeSubmit() {
this.$validator.validateAll().then((result) => {
if (result) {
this.button_title = 'One moment ...';
let submitted_user_data = {
'username': this.emailAddress,
'client_id': this.user_uuid,
'password': this.password,
}
MerchantServices.do_user_login(submitted_user_data)
.then(response => {
let access_token = response.data.access_token;
this.postLogin(access_token);
})
.catch(error => {
this.$refs.invalid_credentials.open();
this.button_title = 'Sign in'
});
return;
}
});
},
postLogin: function(access_token_val) {
if(access_token_val != ''){
setTimeout(() => {
const auth = {
accessToken: access_token_val
}
this.$store.commit('update', auth)
Cookie.set('auth', auth)
this.$refs.invalid_credentials.open();
this.button_title = 'Sign in'
this.$router.push('/app/dashboard')
}, 1000)
}else{
alert('hello')
}
},
and the last user login api call which also returns the token.
do_user_login(user){
var user_details = 'username='+user.username+'&client_id='+ user.client_id +'&grant_type=password&password='+user.password+''
return axios.post('myapiurl', user_details )
.then(response => {
return response;
});
},
Acording to Nuxt Docs req is not available on nuxt generate.
You should use nuxt build and than nuxt start after that.

Passport middleware, check if the user already has a living session from

I am building a web application using angular-fullstack. The stack is using express-sessions for session storage (in Mongodb) and passport.js for authentication.
I want to limit each user to a single login session. I am trying find a way to check if a user already has a living session when they login.
Is there a way to programmatically call a route to query mongodb from the passport middleware?
'use strict';
import path from 'path';
import passport from 'passport';
import {Strategy as LocalStrategy} from 'passport-local';
import express from 'express';
import session from 'express-session';
import _ from 'lodash';
import Session from '../../api/session/session.model';
var app = express();
require('run-middleware')(app);
function localAuthenticate(User, email, password, done, req) {
User.findOne({
email: email.toLowerCase()
}).exec()
.then(user => {
if (!user) {
return done(null, false, {
message: 'This email is not registered.'
});
}
// HERE is where I am trying to check if a user
// already has a living session when they login
// I tried to use the runMiddleware
// to query mongodb for all the existing sessions
// but I get this error: http://pastebin.com/YTeu5AwA
app.runMiddleware('/sessions',{},function(code,data){
console.log(code) // 200
console.log(data) // { user: '20', name: 'Moyshale' }
});
// Is there a way to access and use an existing route?
user.authenticate(password, function(authError, authenticated) {
if (authError) {
return done(authError);
}
if (!authenticated) {
return done(null, false, { message: 'This password is not correct.' });
} else {
return done(null, user);
}
});
})
.catch(err => done(err));
}
export function setup(User, config) {
passport.use(new LocalStrategy({
passReqToCallback: true,
usernameField: 'email',
passwordField: 'password' // this is the virtual field on the model
}, function(req, email, password, done) {
return localAuthenticate(User, email, password, done, req);
}));
}
Ok, I figured it out and I'll try and explain what I did. My specific implementation required me to set up user 'seats', where each user is part of a group and each group is limited in N number of logins at a single time.
As I mentioned in the question, I am using the angular fullstack yeoman generator, so this solution is specific to that setup.
I created a 'sessions' API endpoint so that I could query and modify the sessions stored in the mongo db. I included a 'seat' record with type Number into the sessions model. This is used to keep track of the users seat status for each session. Each user is given a 'loginSeat' value which is used to populate this filed. Also the session now has a seatAllowed of type Boolean, true: the user is allowed to access the site, false: the user is not allowed access to the site.
'use strict';
import mongoose from 'mongoose';
var SessionSchema = new mongoose.Schema({
_id: String,
session: String,
expires: Date,
seat: Number,
seatAllowed: Boolean // true: the user is allowed to access the site, false: the user is not allowed access to the site
});
export default mongoose.model('Session', SessionSchema);
I modified server/auth/login/passport.js so that when a user logs into the site, all other users with a matching seat are bumped out.
'use strict';
import path from 'path';
import passport from 'passport';
import {Strategy as LocalStrategy} from 'passport-local';
import _ from 'lodash';
import Sessions from '../../api/session/session.model';
function saveUpdates(updates) {
return function(entity) {
var updated = _.merge(entity, updates);
return updated.save()
.then(updated => {
return updated;
});
};
}
function localAuthenticate(User, email, password, done, req) {
User.findOne({
email: email.toLowerCase()
}).exec()
.then(user => {
if (!user) {
return done(null, false, {
message: 'This email is not registered.'
});
}
// When a user logs into the site we flag their seat as allowed
var updateSession = {'seat': user.loginSeat, 'seatAllowed': true};
Sessions.findById(req.session.id).exec()
.then(saveUpdates(updateSession))
// When a user logs into the site, we disallow the seats of all other sessions with matching seat
Sessions.find().exec()
.then(sessions => {
// Check for existing user logged in with matching login seat
for (var i = 0; i < sessions.length; i++) {
if (sessions[i].seat === user.loginSeat && sessions[i].id !== req.session.id) {
console.log('DISALOW SEAT:');
var updateSession = {'seatAllowed': false};
Sessions.findById(sessions[i].id).exec()
.then(saveUpdates(updateSession));
}
}
});
user.authenticate(password, function(authError, authenticated) {
if (authError) {
return done(authError);
}
if (!authenticated) {
return done(null, false, { message: 'This password is not correct.' });
} else {
return done(null, user);
}
});
})
.catch(err => done(err));
}
export function setup(User, config) {
passport.use(new LocalStrategy({
passReqToCallback: true,
usernameField: 'email',
passwordField: 'password' // this is the virtual field on the model
}, function(req, email, password, done) {
return localAuthenticate(User, email, password, done, req);
}));
}
Each time the client makes a request the isAuthenticated function is triggered. This is where I check for the seaAllowed boolean for the current session, if true, allow the user to access the site, otherwise logout the user:
function saveUpdates(updates) {
return function(entity) {
var updated = _.merge(entity, updates);
return updated.save()
.then(updated => {
return updated;
});
};
}
/**
* Attaches the user object to the request if authenticated
* Otherwise returns 403
*/
export function isAuthenticated() {
return compose()
// Validate jwt
.use(function(req, res, next) {
// Allow access_token to be passed through query parameter as well
if (req.query && req.query.hasOwnProperty('access_token')) {
req.headers.authorization = 'Bearer ' + req.query.access_token;
}
validateJwt(req, res, next);
})
// Attach user to request
.use(function(req, res, next) {
User.findById(req.user._id).exec()
.then(user => {
if (!user) {
return res.status(401).end();
}
req.user = user;
///////////////////////////
// Login seat limitation //
///////////////////////////
// Check if the user seat is allowed
Sessions.findById(req.session.id).exec()
.then(thisSession => {
// TODO access the session in a better way
if (thisSession.seatAllowed === false || thisSession.seatAllowed === undefined) {
res.redirect('/login');
}
})
next();
})
.catch(err => next(err));
});
}
Thats it.