I am totally new on using JWT and tokens; I just tried to do this:
console.log("logged " + data);
//prints { _id: 5a82ee98e918b22e83d6c3e0,
//username: 'test2',
//name: 'test',
//surname: '2',
//password: '...'
//[etc]
//}
console.log("logged _id " + data._id);
//prints 5a82ee98e918b22e83d6c3e0
var token = jwt.sign(data._id, secret, {
expiresIn: "24h" // expires in 24 hours
});
console.log("saved token " + token);
//prints the token in style eyJhbGciOi[...].eyJfYnNvbn[...].usoLRz-[...]
console.log("decoded: " + JSON.stringify( jwt.decode(token) ) )
//prints the token in this way:
//{"_bsontype":"ObjectID","id":{"type":"Buffer","data":[90,130,238,152,233,24,178,46,131,214,195,224]},"iat":1519502719,"exp":1519589119}
why it does not prints the id number in plain text?
how can i get the id number i put in the token?
UPDATE:
I am in a login function; data is the answer after login, and it contains the user logged in; i have
var login = function(req, res) {
passport.authenticate('local', function(err, data, info) {
if (err) { console.log(err);
}
console.log("data in auth " + data);
if (!data) {
return res.status(404);
}
req.logIn(data, function(err) {
if (err) {
console.log("err " + err);
}
console.log("logged " + data);
console.log("logged _id " + data._id);
var token = jwt.sign[continues on top]
[...]
}
You are not decoding your token correctly
let decodedData = JWT.decode(token,secret);
console.log(decodedData._id);
No need to stringify your data. It will work fine. If you get any error, contact me anytime.
Solved.
Problem was that i put in the token data._id directly as string; as this link says, token payload must be built this way:
{
"_id" : data._id
}
so I do NOT have to do this:
console.log("logged _id " + data._id);
//WRONG
var token = jwt.sign( data._id, secret, {
expiresIn: "24h"
});
but I do have to do THIS WAY:
console.log("logged _id " + data._id);
var myId = {
"_id" : data._id
}
var token = jwt.sign( myId, secret, {
expiresIn: "24h"
});
so now if I use
let decodeddata = jwt.decode(token,secret);
console.log("decoded: " + JSON.stringify(decodeddata,null,4) )
then THIS WORKS.
Thanks to all for helping me finding the issue!
Related
I have a large function that says, okay add this employee to the db based on what the admin entered. But now I need to check, does this user already exist in the db. so I created a function that does just that called getEmployeeNum, but I need to perform a .then in the main function of /addEmployee to say, see what the result of the function getEmployeeNum is before you perform any of the other requests. see the code below:
app.post('/addEmployee', (req, res) => {
if (req.session.loggedin) {
var firstname = req.body.firstname;
var lastname = req.body.lastname;
var username = req.body.username;
var sales = req.body.sales;
var salary = req.body.salary;
var location = req.body.location;
var role = req.body.role;
var admin = req.body.admin;
var employeenum = req.body.employee_num;
var phonenum = req.body.phone_num;
var org = req.body.org;
var pass = "";
var newPassword = req.body.password
getEmployeeNum(req, res, employeenum)
bcrypt.hash(newPassword, saltRounds, function(err, hash) {
pass = hash
addLogin(req, res, pass, firstname, lastname, username, sales, salary, location, role, admin, employeenum, phonenum)
});
var addEmployee = "insert into EMPLOYEES (FIRSTNAME, LASTNAME, USERNAME, SALES, SALARY, LOCATION, ROLE, ADMIN, EMPLOYEE_NUM, PHONENUM, ORGANIZATION) VALUES ('" +
req.body.firstname +
"', '" +
req.body.lastname +
"', '" +
req.body.username +
"', '" +
req.body.sales +
"', '" +
req.body.salary +
"', '" +
req.body.location +
"', '" +
req.body.role +
"', '" +
req.body.admin +
"', '" +
req.body.employee_num +
"', '" +
phonenum +
"', '" +
org +
"' )";
ibmdb.open(ibmdbconnMaster, function(err, conn) {
if (err) return console.log(err);
conn.query(addEmployee, function(err, rows) {
if (err) {
console.log(err);
}
registerEmail(username, firstname, lastname, req, res)
res.redirect('/employees')
})
})
} else {
res.render('login.ejs')
}
})
function getEmployeeNum(req, res, employeenum) {
var getEmployeeNum = "select * from employees"
ibmdb.open(ibmdbconnMaster, function(err, conn) {
if (err) return console.log(err);
conn.query(getEmployeeNum, function(err, rows) {
if (err) {
console.log(err);
}
for (var i = 0; i < rows.length; i++) {
var employee_num = rows[i]["EMPLOYEE_NUM"]
if (employeenum == employee_num) {
alert("employee already exists")
res.render("addEmployee.ejs")
}
}
conn.close(function() {
// console.log("closed the function /index");
});
});
})
}
is this the right way to do it, or is there a better way? Thanks :)
I see that you're using the callback version of SQL driver. I'll assume that you;re working with mysql2 for simplicity wise.
There is actually a promise version of mysql2 driver
const mysql = require('mysql2/promise');
I'll share with you some of the common patterns I use when working with DB.
// Create a pool for connection
const pool = mysql.createPool({
connectionLimit: process.env.SQL_CON_LIMIT,
host: process.env.SQL_SERVER,
port: process.env.SQL_PORT,
user: process.env.SQL_USERNAME,
password: process.env.SQL_PASSWORD,
database: process.env.SQL_SCHEME,
timezone: process.env.SQL_TIMEZONE,
});
// To use async to test the connection via conn.ping() before launch server
const p1 = (async () => {
const conn = await pool.getConnection();
await conn.ping();
conn.release();
return true;
})();
// test connection for SQL, add other into array as you like
Promise.all([p1])
.then(() => {
app.listen(PORT, () =>
console.info(
`Application started on port http://localhost:${PORT}/ at ${new Date()}`
)
);
})
.catch((err) => {
console.error('Cannot connect: ', err);
});
The code block above is for setting up, and test connection before starting the server. This can avoid the rare case where DB is not initialized before the request came in (As the server can start before connecting to DB)
const makeQuery = (query, pool) => {
return async (args) => {
const conn = await pool.getConnection();
try {
let results = await conn.query(query, args || []);
return results[0]; // Result of query is in index 0
} catch (error) {
console.log(error);
} finally {
conn.release();
}
};
};
// Sample query
const queryCheckLogin =
'SELECT COUNT(*) as "match" FROM user WHERE user_id = ? AND password = ?';
// Make it into function!
const checkLogin = makeQuery(queryCheckLogin, pool);
app.post('/api/login', async (req, res) => {
let { user_id, password } = req.body;
// Obtain sha1 password from submitted password
password = sha1(password);
try {
let results = await checkLogin([user_id, password]);
// Return the credential (supposedly token) when record is matched
if (results[0]['match'] !== 0) {
res.status(200).json({ login: 'success', user_id, password });
} else {
// return 401 if record not found
res.status(401).json({ error: 'No such username or password' });
}
} catch (error) {
console.log(error);
res.status(400).json(error);
}
});
The code block above shows the factory function to deal with the general form of getting the result from a query, so you won't clutter the logic in middleware. So you will write out whatever query you will do, make it into function via makeQuery, and just use the resulting function.
Using async...await will also make the code cleaner, however, this depends on the version of codebase you're working on. However, the sample above do works for .then as well.
have a strange thing happening running a Google cloud function. The function starts and logs the user id and job id as expected. Then it calls firestore db and basically sits there for 1 minute, sometimes 2 before it executes the first call... It was even timing out on 240 seconds.
const AWS = require('aws-sdk');
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.run = functions.https.onCall((data, context) => {
var id = data.id;
var userid = data.uid;
var retry = data.retry;
var project;
var db = admin.firestore();
var storage = admin.storage();
console.log("Starting Collect");
console.log("UID: " + userid);
console.log("id ID: " + id);
// Times out on this call
db.collection("users").doc(userid).collection("ids").doc(id).get().then(function(doc) {
console.log("Loaded DB");
project = doc.data();
createexport();
}).catch(function(err) {
console.log(err);
error('Loading DB Error, ' + err, false);
});
function createexport() {
db.collection("exports").doc(id).set({
status: 'Collecting',
stage: 'Export Checker',
percent: 0,
id: id,
}).then(function() {
console.log("Creating Export");
setdb();
}).catch(function(err) {
error("Error creating export in database :" + err, true)
});
}
function setdb() {
db.collection("users").doc(userid).collection("ids").doc(id).update({
status: 'Analyzing Files',
stage: 'Collecting'
}).then(function() {
getaudio();
}).catch(function(err) {
error("Error updating users id in database :" + err, true)
});
}
function getaudio() {
const from = userid + '/projects/' + project.originalproject.id + '/audio.' + project.originalproject.extension;
const to = userid + '/' + id + '/audio.' + project.originalproject.extension;
storage.bucket('---------').file(from).copy(storage.bucket('---------').file(to)).then(function() {
console.log("Collecting files");
copy2();
}).catch(function(err) {
error('Collecting Audio Error, ' + err, true);
});
}
function copy2() {
const from = userid + '/projects/' + project.originalproject.id + '/overlay.png';
const to = userid + '/' + id + '/overlay.png';
storage.bucket('--------.appspot.com').file(from).copy(storage.bucket('---------').file(to)).then(function() {
updateexport();
}).catch(function(err) {
error('Collecting Overlay Error, ' + err, true);
});
}
function updateexport() {
db.collection("exports").doc(id).update({ status: "Waiting" }).then(function() {
console.log("All files collected");
return { status: 'Success' };
}).catch(function(err) {
error("Error creating export entry in database :" + err, true)
});
}
function error(evt, evt2) {
AWS.config.update({ region: "us-east-1" });
var html;
var sub = 'Error with id ' + id;
console.log(evt);
if (evt2) {
db.collection('users').doc(userid).collection('ids').doc(id).update({
status: 'Error'
}).catch(function(err) {
console.log(err);
});
db.collection("exports").doc(id).update({
status: 'Error',
stage: 'Collecting',
error: evt,
}).catch(function(err) {
console.log(err);
});
html = `
Username: ${project.username} <br>
UserID: ${userid} <br>
Email: ${project.email} <br>
id: ${id}
`
} else {
html = `id: ${id}<br>
UserID: ${userid} <br>
Message: Error logged was: ${evt}
`
}
var params = {
Destination: {
ToAddresses: [
'errors#mail.com'
]
},
Message: {
Body: {
Html: {
Charset: "UTF-8",
Data: html
},
},
Subject: {
Charset: 'UTF-8',
Data: sub
}
},
Source: 'errors#mail.com',
ReplyToAddresses: [
project.email
],
};
var sendPromise = new AWS.SES({
apiVersion: "2010-12-01",
"accessKeyId": "-----------",
"secretAccessKey": "------------------------",
"region": "--------",
}).sendEmail(params).promise();
sendPromise.then(function(data) {
return { data: data };
}).catch(function(err) {
return { err: err };
});
}
});
Seems to me to be way too long for a database call of only a few kb. I will attach the cloud log to show time difference. After this initial slump it then performs as expected.
Cloud log image
Anyone got any ideas as to why this could be happening? Many thanks...
Your function is appearing to hang because it isn't handling promises correctly. Also, it doesn't appear to be sending a specific response to the client app. The main point of callable functions is to send a response.
I suggest reviewing the documentation, where you will learn that callable functions are required to return a promise that resolves with an object to send to the client app, after all the async work is complete.
Minimally, it will take a form like this:
return db.collection("users").doc(userid).collection("files").doc(id).get().then(function(doc) {
console.log("Loaded DB");
project = doc.data();
return { "data": "to send to the client" };
}
Note that the promise chain is being returned, and the promise itself resolves to an object to send to the client.
I'm running Express with Sequelize/MariaDB and Passport.js for user authentication.
I'm in the signup part (which works) but I can't seem to render and return an activation email asking them to confirm their email.
passport.js (containing authentication strategies)
passport.use('user-signup-email', new LocalStrategy({
//Process/validate input, check database for existing emails, create user, add to database...
...
if (newUser) {
var token = jwt.sign( { data: newUser.id }, newUser.login_pass + "-" + newUser.account_created);
var URLdata = {
id: newUser.id,
expiration_time: Date.now() + 86400000, //24 hours
url: token,
email_info: mail.createActivationEmail(req.app, newUser.login_key, newUser.user_alias, token)
};
console.log("info: " + URLdata.email_info);
...
//Store dynamic URL and email contents (in case of resending) in database with expiration time
//And then send the email that was just rendered
}
mail.js
exports.createActivationEmail = (app, recipientAddress, userName, url) => {
app.render('emails/activation_email', {
layout: false,
page_title: 'Please confirm your account!',
dynamic_url: url
}, function(err, rendered) {
if (err) {
console.log("Q [" + err + "]");
}
console.log("R " + rendered.toString());
return {
from: adminEmailAddress,
to: recipientAddress,
cc: false,
bcc: false,
subject: 'Welcome to example.com ' + userName + '!',
html: rendered.toString(),
text: "TO DO"
};
});
};
The last console.log in passport.js displays "info: undefined."
But if I print the output in the mail.js module before returning it, it is fine.
I'm guessing it's an async problem? How would I fix it?
I'm still a little unclear on promises and async-await blocks in this context.
Thanks in advance for any help you can offer!
You misunderstood callback functions.
callbacks are (should, when you write them) asynchron:
https://nemethgergely.com/async-function-best-practices/
How to write asynchronous functions for Node.js
I changed your createActivationEmail function.
The last argument is now a callback, thats get invoked when your code app.redner is done.
passport.use('user-signup-email', new LocalStrategy({
//Process/validate input, check database for existing emails, create user, add to database...
// ...
if(newUser) {
var token = jwt.sign({ data: newUser.id }, newUser.login_pass + "-" + newUser.account_created);
mail.createActivationEmail(req.app, newUser.login_key, newUser.user_alias, token, (err, email_info) => {
var URLdata = {
id: newUser.id,
expiration_time: Date.now() + 86400000, //24 hours
url: token,
email_info
};
console.log("info: " + URLdata.email_info);
//...
//Store dynamic URL and email contents (in case of resending) in database with expiration time
//And then send the email that was just rendered
});
}
}));
exports.createActivationEmail = (app, recipientAddress, userName, url, done) => {
app.render('emails/activation_email', {
layout: false,
page_title: 'Please confirm your account!',
dynamic_url: url
}, function(err, rendered) {
if (err) {
console.log("Q [" + err + "]");
cb(err);
return;
}
console.log("R " + rendered.toString());
done(null, {
from: adminEmailAddress,
to: recipientAddress,
cc: false,
bcc: false,
subject: 'Welcome to example.com ' + userName + '!',
html: rendered.toString(),
text: "TO DO"
});
});
};
I'm simply sending a notification when someone new has followed you, but when I try to return the users username in the notification it just says "undefined has decided to follow you" instead of the username.
exports.observeFollowing = functions.database.ref('/following/{uid}/{followingId}').onCreate((snapshot,context) => {
var uid = context.params.uid;
var followingId = context.params.followingId;
console.log('User: ' + uid + 'is following: ' + followingId);
return admin.database().ref('/users/' + followingId).once('value', snapshot => {
var userWeAreFollowing = snapshot.val();
return admin.database().ref('/users/' + uid).once('value', snapshot => {
var userDoingTheFollowing = snapshot.val();
var payload = {
notification: {
title: "Someone new has followed you",
body: userWeAreFollowing.username + " has decided to follow you...",
sound: 'default'
}
}
admin.messaging().sendToDevice(userWeAreFollowing.fcmToken, payload)
.then((response) => {
console.log('Successfully sent message:', response);
return response
})
.catch((error) => {
console.log('Error sending message:', error);
});
})
})
Instead of
body: userWeAreFollowing.username + " has decided to follow you...",
should't be the following user name
body: userDoingTheFollowing.usernames + " has decided to follow you...",
and notice in your realtime database you saved the username as usernameS, that might be the problem
I am using a button to go to the delete route and I am passing to it a key to identify which team to delete. Instead of deleting just one team it deletes ALL teams when using the route. Any ideas?
Delete button:
button#teamDelete.btn.btn-danger.btn-mini(type="submit", value="Delete Team") Delete
script(type='text/javascript')
$('#teamDelete').live('click',function(){
var teamId = #{teamData.key};
$.post('/team/' + teamId, { _method : 'delete' }, function(response) {
console.log(response);
});
});
Team routes:
app.get('/team'/*, lim("Must be logged in to see teams")*/, getAllTeams, function(req, res){
util.log('Serving request for url [GET] ' + req.route.path);
// Pass it the list of all Teams
res.render('team', {'teamsList' : req.teamsList} );
});
/**
* POST /team
* Save new Team
*/
app.post('/team', function(req, res) {
util.log('Serving request for url [POST] ' + req.route.path);
// Output to console the contents of req.body
// console.log('body: ', req.body);
// console.log('body.teamForm: ', req.body.teamForm);
// console.log('body.teamForm.name: ', req.body.teamForm.name);
// console.log('body.teamForm.teamKey: ', req.body.teamForm.teamKey);
// Get data from teamForm
var teamForm = req.body.teamForm;
// Save team in teamForm as new Team
var name = teamForm.name;
var team = new Team();
team.name = name;
// Save new Team to datbase
team.save(function(err){
var message = '';
var retStatus = '';
// No error - Successful Save
if(!err){
util.log('Successfully created new team: ' + name);
message = 'Successfully created new team: ' + name;
retStatus = 'success';
}
// Error - Unsuccessful Save, show error
else {
util.log('Error while creating team: ' + name + ' error : ' + util.inspect(err));
if(err.code === 11000){
message = 'Team already exists';
}
retStatus = 'failure';
}
// Return whether the Save was successful
res.json({
'retStatus' : retStatus,
'message' : message
});
});
});
/**
* GET /team/:key
* Get Team details by key
*/
app.get('/team/:key', function(req, res) {
util.log('Serving request for url [GET] ' + req.route.path);
Team.findByKey(req.params.key, function(err, teamData){
if(!err && teamData){
teamData = teamData;
res.render('teamDetails', { 'teamData' : teamData } );
} else {
util.log('Error in fetching Team by key : ' + req.params.key);
res.json({
'retStatus' : 'failure',
'msg' : 'Error in fetching Team by key ' + req.params.key
});
}
});
});
/**
* DEL /team/:key
* Delete Team by key
*/
app.del('/team/:key', function(req, res) {
util.log('Serving request for url [DEL] ' + req.route.path);
util.log(req.params.key);
Team.remove(req.params.key, function(err){
var message = '';
var retStatus = '';
if (!err) {
util.log('Successfully deleting Team with key: ' + req.params.key);
message = 'Successfully deleting Team with key: ' + req.params.key;
retStatus = 'Success';
} else {
util.log('Error deleting Team with key: ' + req.params.key + 'Error: ' + util.inspect(err));
res.json({
'retStatus' : 'failure',
'msg' : 'Error in fetching Team with key ' + req.params.key
});
}
});
});
Well, you haven't indicated, but I presume Team is a mongoose model, in which case you are not properly specifying your conditions parameter, which must be an object of key/value criteria. Try:
Team.remove({key: req.params.key}, function (err) {});
http://mongoosejs.com/docs/api.html#model_Model.remove