When this code executes, the result is
userId : {
userName : userN
}
when it actually should be the params from the rest call. How can I dynamically add data to ref.update?
exports.addUser = functions.https.onRequest((req, res) => {
const userId = req.query.userId;
const userN = req.query.userName;
var ref = admin.database().ref("users")
ref.update({
userId : {
userName : userN
}
});
res.status(200).send("User added successfully");
});
I guess you need to specify that userId is a variable.
exports.addUser = functions.https.onRequest((req, res) => {
const userId = req.query.userId;
const userN = req.query.userName;
const ref = admin.database().ref("users")
ref.update({
[userId]: {
userName: userN,
},
});
res.status(200).send("User added successfully");
});
PS: I don't know firebase
Related
I'm very new to backend development and I'm trying to figure out how to send my form data from front to backend. I watched a youtube tutorial on how and this is my code for server.js:
const express = require("express");
const app = express();
const port = 2009;
app.use(express.static("public"));
app.use(express.json());
app.get("/", (req, res) => {
res.status(200).json({info: "something"});
});
app.post("/", (req, res) => {
const { parcel } = req.body;
if (!parcel) {
return res.status(400).send({status: "failed"});
}
res.status(200).send({status: "recieved"});
});
app.listen(port, () => console.log(`server.js running on port: ${port}`));
And here is the code for script.js for my form:
const submit = document.getElementById("submit");
const userName = document.getElementById("user");
const password = document.getElementById("pass");
const email = document.getElementById("mail");
const baseUrl = "http://localhost:2009/"
async function post(e) {
e.preventDefault();
const res = await fetch(baseUrl + "website?key=hello", {
method: "POST"
})
}
Like I said I basically have no clue what I am doing could someone help me?
I haven't tested it yet because I'm afraid it won't work if would be very helpful if someone could show me some code or point me to some documentation so that I can work in the right direction.
you seem to be on the right track just a few changes and additions.
const registerForm = document.getElementById('register_form');
async function post(e) {
const form = document.forms.register_form;
const email = form.email.value;
const password = form.password.value;
const username = form.username.value;
try {
const res = await fetch(baseUrl + "website?key=hello", {
method: "POST",
body: JSON.stringify({
email,
username,
password,
}),
headers: { "Content-Type": "application/json" },
});
// handle the response here
} catch (error) {
// handle error here
}
}
registerForm.addEventListener('submit', post, false);
on the backend, you will need a route to handle this request
app.post("/", (req, res) => {
const { username, email, password } = req.body;
// validate the data from the request
if (!username || !email || !password) {
return res.status(400).send({
status: "failed",
message: "fields are required"
});
}
res.status(201).send({status: "recieved"});
});
StatusCode 201 indicates a new resource has been created
References:Using Fetch Api statusCode
I hope this helps.
I'm trying to implement JWT authentication, and I can't figure out why in Postman protected-route is available, while in my browser protected-route is Unauthorized.
I'm a beginner and its first time implementing jwt authentication in my project following this tutorial https://www.youtube.com/playlist?list=PLYQSCk-qyTW2ewJ05f_GKHtTIzjynDgjK
Problem
/login and /register work fine and I can see from the log they issue a JWT token in the req.headers
like 'Authorization':'Bearer <token>', however when I try to access GET /protected-route in my browser, it returns Unauthorized, and I can see no logging from JWTStrategy.
I think req.headers.Authorization is not set to all HTTP requests in the app, but only to POST /login, /register routes So my questions are:
Is this req.headers["Authorization"] = 'Bearer <toekn>'; correct way to set req headers to all GET and POST request in the app?
Does the jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken() checks for Authorization property in req.headers or res.headers?
I have provided the relevant code snippets please have a look!
Code:
app.js
//...
require('./config/database'); // require the db
// ...
const passport = require('passport');
const strategy = require('./config/passport').strategy;
// ...
app.use(passport.initialize());
passport.use(strategy);
// ...
module.exports = app
router/index.js
const router = express.Router();
//...
const User = require('../config/database').User;
const passport = require('passport');
const utils = require('../lib/utils');
// register route
router.post('/register', function(req, res, next){
const saltHash = utils.genPassword(req.body.password);
console.log("req.body.password is: " + req.body.password)
const salt = saltHash.salt;
const hash = saltHash.hash;
const newUser = new User({
username: req.body.username,
hash: hash,
salt: salt
})
newUser.save()
.then((user) => {
const jwt = utils.issueJWT(user);
if (jwt){
req.headers["Authorization"] = jwt.token;
}
res.redirect('/login')
})
.catch(err => next(err))
});
// login route
router.post('/login', function(req, res, next){
User.findOne({username: req.body.username})
.then((user) => {
if(!user) {
res.status(401).json({success: false, msg: "Could not find user "})
}
// validate the user
const isValid = utils.validPassword(req.body.password, user.hash, user.salt)
if(isValid) {
// issue a JWT
const jwt = utils.issueJWT(user);
if (jwt){
req.headers["Authorization"] = jwt.token;
}
res.redirect("/")
} else {
res.status(401).json({success: false, msg: "you entered the wrong password"})
}
})
.catch(err => next(err))
});
// GET protected route
router.get("/protectd-route", passport.authenticate('jwt', {session: false}), async (req, res, next) => {
res.render("user/getuser.pug")
next()
})
passport.js
const User = require('../config/database').User;
// ...
const Strategy = require('passport-jwt').Strategy;
const ExtractJwt = require('passport-jwt').ExtractJwt;
/// PUB_KEY
const pathToKey = path.join(__dirname, '..', 'id_rsa_pub.pem');
const PUB_KEY = fs.readFileSync(pathToKey, 'utf8');
// options
const options = {
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: PUB_KEY,
algorithms: ['RS256']
};
// strategy
const strategy = new Strategy(options, (payload, done) => {
User.findOne({_id: payload.sub})
.then((user) => {
if(user) {
return done(null, user)
} else {
return done(null, false)
}
})
.catch((err) => done(err, null))
});
module.exports.strategy = strategy;
utils.js
genPassword() - Creating a salt and hash out of it to store in db
validPassword() - re-hashing user salt and hash to verify
issueJWT() - signing user with jsonwebtoken
const crypto = require('crypto');
const jsonwebtoken = require('jsonwebtoken');
const User = require('../config/database').User;
//...
const pathToKey = path.join(__dirname, '..', 'id_rsa_priv.pem');
const PRIV_KEY = fs.readFileSync(pathToKey, 'utf8');
// validate in /login
function validPassword(password, hash, salt) {
var hashVerify = crypto.pbkdf2Sync(password, salt, 10000, 64, 'sha512').toString('hex');
return hash === hashVerify;
}
// generate in /register
function genPassword(password) {
var salt = crypto.randomBytes(32).toString('hex');
var genHash = crypto.pbkdf2Sync(password, salt, 10000, 64, 'sha512').toString('hex');
return {
salt: salt,
hash: genHash
};
}
// sign
function issueJWT(user) {
const _id = user._id;
const expiresIn = '86400';
const payload = {
sub: _id,
iat: Date.now()
};
const signedToken = jsonwebtoken.sign(payload, PRIV_KEY, { expiresIn: expiresIn, algorithm: 'RS256' });
return {
token: "Bearer " + signedToken,
expires: expiresIn
}
}
module.exports.validPassword = validPassword;
module.exports.genPassword = genPassword;
module.exports.issueJWT = issueJWT;
Postman
In Postman, the protected route is showing successfully, with Headers set as above.
The browser network is showing this, there is no Authorization property both in response and request headers
Clearly, I'm missing something, but I can't figure it out. Any help is appreciated
here is also my db
database.js
const uri = process.env.MONGO_URI
const connection = mongoose.connection;
mongoose.connect(uri, {
useUnifiedTopology: true,
serverSelectionTimeoutMS: 5000
})
connection.on('error', console.error.bind(console, "connection error"))
connection.once('open', () => {
console.log('MongoDB database connection has been established successfully')
})
const userSchema = new mongoose.Schema({
username: String,
hash: String,
salt: String
});
const User = mongoose.model('User', userSchema )
module.exports.User = User;
I am building a MEVN stack CRUD app (Vue, Node, Express, MongoDB). I am attempting to set up the following Express route for my app...
postRoutes.post('/update/:id', async(req, res)=> {
const collection = await loadPostsCollection();
let id = req.params.id;
let result = await collection.findOne(req.params.id)
if (!result) {
res.status(404).send("data is not found");
}
else {
result.title = req.body.title;
result.body = req.body.body;
result.updateOne();
}
});
..in order to update specific data based on the id of that data. After clicking the update button on the front end and triggering an updatePost() method...
updatePost() {
let uri = `http://localhost:4000/posts/update/${this.$route.params.id}`;
this.axios.post(uri, {
title: this.post.title,
body: this.post.body
}).then(() => {
this.$router.push({name: 'posts'});
});
}
...the express route above does not execute. I also tried configuring the route like so...
postRoutes.post('/update/:id', async(req, res)=> {
const collection = await loadPostsCollection();
let id = req.params.id;
let result = await collection.findOne({
_id: new mongodb.ObjectId(id)
});
if (!result) {
res.status(404).send("data is not found");
}
else {
result.title = req.body.title;
result.body = req.body.body;
result.updateOne();
}
});
But this also did not work. Any idea how to set up an update route?
Here are all of my routes:
const express = require('express');
const postRoutes = express.Router();
const mongodb = require('mongodb')
postRoutes.get('/', async (req, res) => {
const collection = await loadPostsCollection();
res.send(await collection.find({}).toArray());
});
postRoutes.post('/add', async (req, res) => {
const collection = await loadPostsCollection();
let task = req.body;
await collection.insertOne(task);
res.status(201).send();
});
postRoutes.get("/edit/:id", async (req, res) => {
const collection = await loadPostsCollection();
let id = req.params.id;
let result = await collection.findOne({
_id: new mongodb.ObjectId(id)
});
if (!result) {
return res.status(400).send("Not found");
}
res.status(200).send(result);
});
postRoutes.post('/update/:id', async(req, res)=> {
const collection = await loadPostsCollection();
let id = req.params.id;
let result = await collection.findOne({
_id: new mongodb.ObjectId(id)
});
// let result = await collection.findOne(req.params.id)
if (!result) {
res.status(404).send("data is not found");
}
else {
result.title = req.body.title;
result.body = req.body.body;
result.updateOne();
}
});
postRoutes.delete('/delete/:id', async (req, res, next) => {
const collection = await loadPostsCollection();
collection.deleteOne({ _id: mongodb.ObjectId(req.params.id) });
res.status(200).send({});
});
async function loadPostsCollection() {
const client = await mongodb.MongoClient.connect(
'mongodb+srv://jsfanatik:1qaz2wsx#cluster0-lv686.mongodb.net/test?retryWrites=true&w=majority',
{
useNewUrlParser: true
}
);
return client.db("test").collection("todos")
}
module.exports = postRoutes;
You request URL is /posts/update/:id but I don't see that path in any express router.
You are missin /posts in your router
postRoutes.post('/update/:id', async(req, res)=> {
const collection = await loadPostsCollection();
let id = req.params.id;
let result = await collection.findOne(req.params.id)
if (!result) {
res.status(404).send("data is not found");
}
else {
result.title = req.body.title;
result.body = req.body.body;
result.updateOne();
}
});
I'm a beginner in NodeJS and I've tried to make an authentication form using NodeJS + express. I want to make a validation for my password (when "confirmpassword" is different than "password" it should return nothing. Unfortunately, I keep getting "data and salt arguments required". I tried in different ways, to put some conditions, but I keep getting this error. Any ideas how I should make it work?
Here is the file user.js:
const pool = require('./pool');
const bcrypt = require('bcrypt');
function User() {};
User.prototype = {
find : function(user = null, callback)
{
if(user) {
var field = Number.isInteger(user) ? 'id' : 'username';
}
let sql = `SELECT * FROM users WHERE ${field} = ?`;
pool.query(sql, user, function(err, result) {
if(err)
throw err
if(result.length) {
callback(result[0]);
}else {
callback(null);
}
});
},
create : function(body, callback)
{
var pwd = body.password;
var cpwd = body.confirmpassword;
// here i hash the pass
body.password = bcrypt.hashSync(pwd,10);
body.confirmpassword = bcrypt.hashSync(cpwd, 10);
if (body.password != body.confirmpassword){
callback(null);
}
else {
var bind = [];
for(prop in body){
bind.push(body[prop]);
}
let sql = `INSERT INTO users(username, fullname, password) VALUES (?, ?, ?)`;
pool.query(sql, bind, function(err, result) {
if(err) throw err;
callback(result.insertId);
});
}
},
login : function(username, password, callback)
{
this.find(username, function(user) {
if(user) {
if(bcrypt.compareSync(password, user.password)) {
callback(user);
return;
}
}
callback(null);
});
}
}
module.exports = User;
And the file pages.js:
const express = require('express');
const User = require('../core/user');
const router = express.Router();
const user = new User();
router.get('/', (req, res, next) => {
let user = req.session.user;
if(user) {
res.redirect('/home');
return;
}
res.render('index', {title:"My application"});
})
router.get('/home', (req, res, next) => {
let user = req.session.user;
if(user) {
res.render('home', {opp:req.session.opp, name:user.fullname});
return;
}
res.redirect('/');
});
router.post('/login', (req, res, next) => {
user.login(req.body.username, req.body.password, function(result) {
if(result) {
req.session.user = result;
req.session.opp = 1;
res.redirect('/home');
}else {
res.send('Username/Password incorrect!');
}
})
});
router.post('/register', (req, res, next) => {
let userInput = {
username: req.body.username,
fullname: req.body.fullname,
password: req.body.password
};
user.create(userInput, function(lastId) {
if(lastId) {
user.find(lastId, function(result) {
req.session.user = result;
req.session.opp = 1;
res.redirect('/home');
});
}else {
console.log('Error creating a new user ...');
}
});
});
router.get('/logout', (req, res, next) => {
if(req.session.user) {
req.session.destroy(function() {
res.redirect('/');
});
}
});
module.exports = router;
In userInput, you are not passing confirmpassword property.
let userInput = {
username: req.body.username,
fullname: req.body.fullname,
password: req.body.password
};
In create method, you are accessing it.
var cpwd = body.confirmpassword;
cpwd is null, and that's the reason for the error.
body.confirmpassword = bcrypt.hashSync(cpwd, 10);//**cpwd is null**
As per the docs, data is required argument and this cannot be null.
hashSync(data, salt)
data - [REQUIRED] - the data to be encrypted.
salt - [REQUIRED] - the salt to be used to hash the password.
Tried this for updating user information , only phone number but it's not getting update.
router.post('/edit', checkAuth, function (req, res, next) {
console.log(req.userData.userId)
User.update({_id: req.userData.userId}, {$set:req.userData.phoneNo}, function (err){
if (err) {
console.log(err);
}
res.status(200).send(req.userData);
});
});
My user controller const mongoose = require ('mongoose');
const User = mongoose.model('User');
module.exports.register = (req, res, next) =>{
var user = new User();
user.fullName = req.body.fullName;
user.email = req.body.email;
user.password = req.body.password;
user.phoneNumber = req.body.phoneNumber;
user.save((err, doc) =>{
if(!err)
res.send(doc);
else{
if (err.code == 11000)
res.status(422).send(["Entered duplicate email address. Please check"]);
else
return next(err);
}
});
}
And then I am authenticating by passing jwt on this field
phoneNo: user[0].phoneNumber
The auth-token verifies and decode the fields
const token = req.headers.authorization.split(" ")[1];
const decoded = jwt.verify(token, process.env.JWT_KEY)
req.userData = decoded;
Update is not working and getting error message Invalid atomic update value for $set. Expected an object, received string .
first of all, you should use PATCH-method - because you are updating only one item in existed object, in body you should send id of user and new value of certain value. If you use mongoose you can try it
User.findOneAndUpdate({ _id: id }, updatedItem, { new: true }, (err, doc) => {
if (err) return res.send(err.message)
if (doc) return res.send(doc);
})
const id = req.body._id;, if you dont use mongoose you should try findAndModify method
Your code
User.update({_id: req.userData.userId}, {$set:req.userData.phoneNo}
Correct code:
User.update({_id: req.userData.userId}, {$set:{phoneNumber:req.userData.phoneNo}}
Try this method:
User.findByIdAndUpdate(req.userData.userId, { $set:{phoneNumber:req.userData.phoneNo}}, { new: true }, function (err, user) {
if (err) console.log(err);
res.send(user);
});