Firebase auth with PHP, am i using it right? is it secure? - security

So I have a form and in the form i ask the user to enter his phone number to be verified, and then his information will be inserted into DB with PHP queries.
I used this code:
var firebaseConfig = {
apiKey: "******",
authDomain: "*****",
databaseURL: "https://****",
projectId: "*****",
storageBucket: "",
messagingSenderId: "*****",
appId: "1:****:*****"
};
firebase.initializeApp(firebaseConfig);
// Create a Recaptcha verifier instance globally
// Calls submitPhoneNumberAuth() when the captcha is verified
window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier(
"recaptcha-container",
{
size: "normal",
callback: function(response) {
submitPhoneNumberAuth();
}
}
);
// This function runs when the 'sign-in-button' is clicked
// Takes the value from the 'phoneNumber' input and sends SMS to that phone number
function submitPhoneNumberAuth() {
var phoneNumber = document.getElementById("phoneNumber").value;
var appVerifier = window.recaptchaVerifier;
firebase
.auth()
.signInWithPhoneNumber(phoneNumber, appVerifier)
.then(function(confirmationResult) {
window.confirmationResult = confirmationResult;
})
.catch(function(error) {
console.log(error);
});
}
// This function runs when the 'confirm-code' button is clicked
// Takes the value from the 'code' input and submits the code to verify the phone number
// Return a user object if the authentication was successful, and auth is complete
function submitPhoneNumberAuthCode() {
var code = document.getElementById("code").value;
confirmationResult
.confirm(code)
.then(function(result) {
var user = result.user;
console.log(user);
})
.catch(function(error) {
console.log(error);
});
}
//This function runs everytime the auth state changes. Use to verify if the user is logged in
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
console.log("USER LOGGED IN");
} else {
// No user is signed in.
console.log("USER NOT LOGGED IN");
}
});
to verify the user's phone number. and in the form i used this :
<div class="verifyCon">
<div class="SMSBox Padding2">
<div>
<span class="Text3"> phone number </span>
</div>
<div>
<input class="InptText" type="tel" id="phoneNumber" maxlength="10" minlength="10" name="uphone" required>
</div>
<div>
<button type="button" class="SMSBut" onclick="submitPhoneNumberAuth()">
<h2 id="sign-in-button" class="Text2"> send </h2>
</button>
</div>
</div>
<div class="SMSBox Padding2">
<div>
<span class="Text3"> code </span>
</div>
<div>
<input class="InptText" type="text" id="code" name="code" maxlength="6" minlength="6" required>
</div>
<div>
<button type="button" class="SMSBut" onclick="submitPhoneNumberAuthCode()">
<h2 id="check-in-button" class="Text2"> check </h2>
</button>
</div>
</div>
</div>
My questions:
Is it secure? can the user get configuration info from the file? if so how to secure it?
Is there a way to make sure the user won't just submit the form without verifying the phone number?
Do I need to add ReCaptcha in the form page, or the one with auth will be enough?
I'm not good with JavaScript, so please any suggestions will be appreciated.

Related

Post current React state to express server

I have tried a few different ways of doing this but no matter what I've tried I get the same result.
Once I start the server, the first time I post, it doesn't work. because the state hasn't updated (I think)? All of the following post requests afterwards work fine, along with the correct state. So I'm not so sure it's state. Here's my code
Register.js
export default class Register extends React.Component{
constructor(props){
super(props);
this.state = {
username: '',
password: ''
}
}
onChange = (e) => this.setState({[e.target.name]: e.target.value});
register = async () => {
await axios.post(config.API_URI + 'register', {
username: this.state.username,
password: this.state.password
});
}
render(){
return(
<div>
<form id='register-form' className='border'>
<div id='form-title'>Create account</div>
<div className='mb-3'>
<label className='form-label' htmlFor='username-label' name='username-label'>Username</label>
<input type='text' className='form-control' id='usernameInput' name='username' onChange={this.onChange}></input>
</div>
<div className='mb-3'>
<label className='form-label' htmlFor='password-label' name='password-label'>Password</label>
<input type='password' className='form-control' id='password-input' name='password' onChange={this.onChange}></input>
</div>
{/*}
<div className='mb-3'>
<label className='form-label' htmlFor='password-label-confirm' name='password-label-confirm'>Confirm Password</label>
<input type='password' className='form-control' id='password-input-confirm' name='passwordConfirm'></input>
</div>
{*/}
<div id='buttons'>
<button className='btn btn-primary' id='register-btn' onClick={this.register} disabled={this.state.username === '' & this.state.username === ''}>Register</button>
<Link className='btn btn-primary' to='/login' id='login-btn'>Login</Link>
</div>
</form>
</div>
)
}
}
server.js post request (currently just attempting to console.log my request instead of adding to my database). I have gotten it to save to the database just fine following the second post attempt.
...
app.post("/register", (req, res)=>{
try{
if(req.body){
console.log(req.body);
/*
User.find({username: req.body.username}, (err, data)=>{
if(data.length == 0){
let user = new User({
username: req.body.username,
password: req.body.password
});
user.save((err,data)=>{
if(err){
res.status(400).json({
errorMessage: err,
status: false
});
} else {
res.status(200).json({
status: true,
title: 'Registered Successfully'
});
}
});
}
});
*/
}
} catch(e){
res.status(400).json({
errorMessage: 'Something went wrong!',
status: false
})
}
});
I'm a beginner making my first full-stack application
Good night! I cannot comment because I'm too new to Stack Overflow, so I'll say the following as an answer:
I ran your code on my machine and it worked fine but the reload. When I clicked on the "Register" button, I read the current state value by adding console.log(this.state) just before await axios.post(...).
That worked since the first click. However, the page reloads each submition. You missed the event.preventDefault(). This function prevents the reload when submitting a form by clicking on a button inside it. This is the code:
register = async (event) => {
event.preventDefault();
await axios.post('http://localhost:3333/register', {
username: this.state.username,
password: this.state.password
});
}
Then, I ran a Node API with your code. It also console.log(req.body) worked perfectly fine as well.
Therefore, I don't have any other ideas of what could be causing the issue on your machine besides the missing event.preventDefault().
P.S.:
Some features that helps while debugging JavaScript:
Use the command debugger; on your Front-End code. For example, inside the register method. This allows you to stop the execution of the code and inspect all the variables available and their current values. This may help you.
While debugging don't forget to put a lot of console.log on your code in specific parts that could be related to your bug. This helps you understand what's going on.

How Can I Fix this Node.js Login Authentication Page?

I am working on a website with MongoDB, Node.js and Express (no React or Angular). I have the user registration working fine. But my login is not working and I cannot figure out why. Below I post the relevant code:
index.js
/*
* Login Existing User
*/
const loginController = require("./controllers/login")
app.get('/auth/login', loginController);
const loginUserController = require('./controllers/loginUser')
app.post('/users/login', loginUserController)
/controllers/login:
module.exports = (req, res) => {
res.render('login')
}
relevant portion of login.ejs (which is rendered due to preceding code):
<form action="/users/login" method="POST" enctype="multipart/form-data">
<div class="form-floating">
<input class="form-control" id="username" type="text" placeholder="User Name" data-sb-validations="required" name = "username"/>
<label for="title">Username</label>
<div class="invalid-feedback" data-sb-feedback="title:required">A descriptive title is required.</div>
</div>
<div class="form-floating">
<input class="form-control" id="password" type="password" placeholder="Password" data-sb-validations="required" name="password"/>
<label for="name">Password</label>
<div class="invalid-feedback" data-sb-feedback="name:required">Password required.</div>
</div>
<br />
<!-- This is what your users will see when there is-->
<!-- an error submitting the form-->
<div class="d-none" id="submitErrorMessage"><div class="text-center text-danger mb-3">Error sending message!</div></div>
<!-- Submit Button-->
<button class="btn btn-primary text-uppercase" id="submitButton" type="submit">Login</button>
</form>
/controllers/loginUser:
const bcrypt = require('bcrypt')
const User = require('../models/User')
module.exports = (req,res) =>{
const { username,password } = req.body
User.findOne({username: username}, (error,user) => {
if(user){
bcrypt.compare(password, user.password, (error,same)=>{
if(same){
req.session.userId = user._id
res.redirect('/')
}
else{
res.redirect('/auth/login')
}
})
}
else{
console.log("/auth/login::",user)
res.redirect('/auth/login')
}
})
}
I have used Postman and also just tested in Chrome and Firefox and it appears that the GET made to /auth/login appears to work. I get there and I submit my form. But instead of redirecting me to my index or landing page ("/"), it just sends me back to /users/login and, also, the website doesn't recognize that I am logged in. Here is my code to trigger a Boolean if I am logged in:
global.loggedIn = null;
app.use("*", (req, res, next) => {
loggedIn = req.session.userId;
next()
});
Any thoughts/suggestions as to what I am doing wrong are appreciated.

Nodejs blog site wont show current email in the Edit Settings Page

My nodejs blog site wont show my current email in the Edit Settings page. It only shows the correct Name. For Email Edit User settings: it shows: [object Object] The correct email should show for each email from mongodb. Not sure if I need app.get and app.post as well.
app.js:
app.get('/editUserSettings', (req, res) => {
User.findOne({ email: req.body.email }, function(err, user) {
const email = User.findOne(req.body.email)
if (!err) {
res.render("editUserSettings", {
user: user, email: email
});
}
});
});
editUserSettings.ejs
<%- include("partials/header") -%>
<div class="ui main text container segment">
<div class="ui huge header">Edit my Profile </div>
<form class="ui form" action="/editUserSettings/<%= currentUser._id %>?_method=PUT" method="POST">
<div class="field">
<label>Name</label>
<input type="text" name="name" value="<%=currentUser%>" >
</div>
<div class="field">
<label>Email</label>
<input type="text" name="email" value="<%=email %>" >
</div>
<button class="ui violet basic button">Submit</button>
</form>
</div>
<%- include("partials/footer") -%>
your User.findeOne returns an object with your properties defined in the Schema and a unique id to your database entry, try a console.log(email) after the findOne line, it should log something like:
{
_id: XXXXXXXXXXXX,
email: example#youremail.de
}
also if you are using mongoose as a client for mongodb you need to async await your code because User.findOne returns a promise, maybe contact me on my discord lausnens#6598, there i could help you a bit better :)

Looking for advice with AJAX and js

I want to add a new user to mysql database and I know how to make querys with one unique search row but now I got four of them.
4 inputs
<div id="data">
User:
<input type="text" name="UserName" id="name_u"></textarea>
<br>
Password:
<input type="password" name="contraseƱa" id="pass_u">
<br>
Email:
<input type="email" name="email" id="email_u">
<br>
BirthDate:
<input type="date" name="BirthDate" id="bday_u">
<br>
<input value="Registrar" type="button" onclick="add_u()">
</div>
My problem is that I don't know how to make the AJAX and write the js to make them work.
app.get ('/useradd',(req, res)=>{
var name_u = req.query.name_u;
var pass_u = req.query.pass_u;
var email_u = req.query.email_u;
var bday_u = req.query.bday_u;
mysqlConnection.query('INSERT INTO user (UserName, Password, email, BirthDate, level, U_rank) VALUES ()', [search], (err, rows, fields)=>{
if (!err){
console.log(rows);
res.end(rows);
}
else
console.log(err);
})
});
This is the code I'm ussing on my js.
If someone can help me I'll really appreciate it.
Wrap your inputs in < form > not a < div >
<form method="POST" enctype="multipart/form-data" id="myform">
<input type="text" name="title"/><br/><br/>
<input type="file" name="files"/><br/><br/>
<input type="submit" value="Submit" id="btnSubmit"/>
</form>
<h1>jQuery Ajax Post Form Result</h1>
<span id="output"></span>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
Use next javascript to collect and send form data
$(document).ready(function () {
$("#btnSubmit").click(function (event) {
//stop submit the form, we will post it manually.
event.preventDefault();
// Get form
var form = $('#myform')[0];
// Create an FormData object
var data = new FormData(form);
// If you want to add an extra field for the FormData
data.append("CustomField", "This is some extra data, testing");
// disabled the submit button
$("#btnSubmit").prop("disabled", true);
$.ajax({
type: "POST",
enctype: 'multipart/form-data',
url: "/upload.php",
data: data,
processData: false,
contentType: false,
cache: false,
timeout: 800000,
success: function (data) {
$("#output").text(data);
console.log("SUCCESS : ", data);
$("#btnSubmit").prop("disabled", false);
},
error: function (e) {
$("#output").text(e.responseText);
console.log("ERROR : ", e);
$("#btnSubmit").prop("disabled", false);
}
});
});
});

NodeJS not able to get token value from req.params.token

app.post('/reset/:token', function(req, res) {
async.waterfall([
function(done) {
User.findOne({ 'local.resetPasswordToken' : req.params.token, 'local.resetPasswordExpires' : { $gt: Date.now() } }, function(err, user) {
if (!user) {
req.flash('resetMessage', req.params.token);
return res.redirect('back');
}
], function(err) {
res.redirect('/');
});
});
app.get('/reset/:token', function(req, res) {
User.findOne({ 'local.resetPasswordToken': req.params.token, 'local.resetPasswordExpires' : { $gt: Date.now() } }, function(err, user) {
if (!user) {
req.flash('forgotMessage', req.params.token );
return res.redirect('/forgot');
}
res.render('reset.ejs', { user: req.user, message: req.flash('resetMessage') });
});
});
<!--Reset.ejs page ResetPassword FORM -->
<form action="/reset/:token" method="post">
<div class="form-group">
<label>New Password</label>
<input type="text" class="form-control" name="newpassword">
</div>
<div class="form-group">
<label>Confirm Password</label>
<input type="text" class="form-control" name="confirmpassword">
</div>
<button type="submit" class="btn btn-warning btn-lg">Reset</button>
</form>
I able to get the token with req.params.token for the "post" after clicking
http://localhost:8080/reset/fed831abf73150c96f6a3e392b5cbdcaccdeb9bd
Later when I submit through the reset.ejs for the "get" I couldn't retrieved any token value with req.params.token.
Any solution to it?
I imagine that the original code for this might have come from http://sahatyalkabov.com/how-to-implement-password-reset-in-nodejs/. In this tut the jade templating engine is used and if you look at the reset.jade you will see that it starts with
form(method='POST')
but no action is defined. I don't really know jade but in your example you are using ejs and in your code you are setting the action to
form action="/reset/:token" method="post"
and as everybody has pointed out the route that you post to is exactly /reset/:token. So req.params will be :token and the reset will fail. What you need to do is post the url exactly as it appears in the get request. If you read
Is it a good practice to use an empty URL for a HTML form's action attribute? (action="")
you can see that you can amend your reset.ejs page code to read
form action="" method="post"
Now the post should have an action equal to the get url with the token in place and the reset should occur.
you need another form with method='get' and action='reset/' + tokenvar. Also your async waterfall does not call done() so will not call the redirect if the user exists

Resources