lowdb updates only one infos in JSON file - javascript

I make a lowdb request to update a JSON file, but only the date is updated. When I make a console.log of the information to update, this is what I want to update:
res.on("end", function () {
let body = Buffer.concat(chunks);
let final = JSON.parse(body);
if (final.error !== undefined) {
console.log("Initial authentication:", final.error_description, "Please refresh the authentication grant");
extAuthCallback(84);
} else {
tokens.set('access_token', final.access_token)
.set('expires_in', final.expires_in)
.set('refresh_token', final.refresh_token)
.set('refresh_date', moment())
.write()
console.log(final, tokens.value())
extAuthCallback(1);
}
});
console.log of my final variable:
{
access_token: 'oa_prod_iq00cRPk5Jhh4VffSHlDj7DEDsSIlpCRRczI3l3ASC0',
token_type: 'bearer',
expires_in: 2399,
refresh_token: 'oa_prod_nIjBZs74xGvJXi1B-wdMyITfxGyklpCRRczI3l3ASC0'
}
console.log of my JSON file after the request:
{
access_token: 'oa_prod_pB9Q0FFM9Tk4c5n3HMRBFKAVz6naiJ-jmb3QCeBrT00',
expires_in: 2399,
refresh_token: 'oa_prod_nX3EDs530SM8eHv_fM5BN7-5RLBwkrKoUi6uExBbTY4',
refresh_date: '2020-11-28T23:31:13.855Z',
primary_autorization_date: '2020-11-29T00:40:58.421Z'
}
My JSON file after the modifications:
{
"access_token": "oa_prod_pB9Q0FFM9Tk4c5n3HMRBFKAVz6naiJ-jmb3QCeBrT00",
"expires_in": 2399,
"refresh_token": "oa_prod_nX3EDs530SM8eHv_fM5BN7-5RLBwkrKoUi6uExBbTY4",
"refresh_date": "2020-11-28T23:31:13.855Z",
"primary_autorization_date": "2020-11-29T00:40:58.421Z"
}
So it only has the primary_autorization_date field changing...

You should use set instead of update.
tokens.set('access_token', final.access_token)
.set('expires_in', final.expires_in)
.set('refresh_token', final.refresh_token)
.set('refresh_date', moment())
.write()
The update method is accepted a function like this.
db.update('test1', (n) => 5555)
.update('test2', (n) => n + 1)
.write()
If you use set, you just need to assign the value to it.
db.set('test1', 5555).set('test2', 3333).write()
And when you use moment, there are two ways to you could use.
// Way 1 with moment()
db.set('date', moment()).write()
// Way 2 with moment
db.update('date', moment).write()

So the solution is:
I call my function that contains the HTTP request in another file like this:
app.get('/', async function(req, res) {
const access_token = req.query.code;
if (access_token) {
let authentication = await asyncExtAuth(access_token);
if (authentication == 84)
return res.send({error: "Please give a valid access_token"});
res.sendFile(path.join(__dirname + '/success_page/index.html'));
db.set('access_token', access_token).write()
tokens.set('primary_autorization_date', moment()).write()
console.log("Access Token successfully refreshed")
}
else
res.send({error: "Please specify an access token"})
})
In which I modify a second time my file with the line tokens.set('primary_autorization_date', moment()).write(). By doing this, lowdb doesn't take into account the modification made just before and re-modifies my file with the information it contained before. The solution is to add the line tokens.read() just before modifying the file to update the cache:
app.get('/', async function(req, res) {
const access_token = req.query.code;
if (access_token) {
let authentication = await asyncExtAuth(access_token);
if (authentication == 84)
return res.send({error: "Please give a valid access_token"});
res.sendFile(path.join(__dirname + '/success_page/index.html'));
db.set('access_token', access_token).write()
tokens.read()
tokens.set('primary_autorization_date', moment()).write()
console.log("Access Token successfully refreshed")
}
else
res.send({error: "Please specify an access token"})
})

Related

nodemailer verify is returning success even with bad credentials

so I am trying to create a gmail client as a learning project. I am using nodemailer module to verify credentials and send mails. My code is as follows
let data ;
req.setEncoding('utf8') ;
await req.on('data', (chunk) => {
data = query.parse(chunk) ;
});
const mailer = nodemailer.createTransport({service: 'gmail'}) ;
mailer.options.auth = await data ;
mailer.verify((err, suc) => {
if (mailer.options.auth === undefined) {
console.log("No Credentials") ;
}
else if (err) {
console.log("Error : ") ;
} else {
console.log("success") ;
}
}) ;
PS : the function wrapping it is a async arrow function
It is correctly logging "No Credentials" when the post data received from form is empty, It is logging "success" even if entered credentials are wrong. I hope for a solution soon, Thanks in advance.
I've tried it myself and I've came to these 2 conclusions :
I haven't found any way to re-set the auth property after having created the Mail object using createTransport() method. Maybe there is one, maybe not. You're gonna have to look into it.
The verify() method does not check if the auth object is defined but rather checks if the props that it contains are defined and valid
But here's what I did and that works :
// the function returns an object of type { user: string, pass: string }
const credentials = await getMyAuthData();
const config = {
service: 'Gmail',
auth: credentials
};
const mailer = nodemailer.createTransport(config);
mailer.verify((error, success) => {
if (error) throw error;
console.log(success);
});

MS graph api get teams using javascript returns no results

i am using graph api javascript example from here https://learn.microsoft.com/en-us/graph/api/user-list-joinedteams?view=graph-rest-beta&tabs=javascript
and my code is like:
async function(req, res) {
if (!req.isAuthenticated()) {
// Redirect unauthenticated requests to home page
res.redirect('/')
} else {
let params = {
active: { calendar: true }
};
// Get the access token
var accessToken;
try {
accessToken = await tokens.getAccessToken(req);
console.log("access token is:", accessToken)
} catch (err) {
req.flash('error_msg', {
message: 'Could not get access token. Try signing out and signing in again.',
debug: JSON.stringify(err)
});
}
if (accessToken && accessToken.length > 0) {
try {
console.log("vik testing stuff12 for teams")
const user = await graph.getTeams(accessToken)
console.log("graph me:::", user)
} catch (err) {
req.flash('error_msg', {
message: 'Could not fetch events',
debug: JSON.stringify(err)
});
}
} else {
req.flash('error_msg', 'Could not get an access token');
}
res.render('calendar', params);
}
}
getTeams is
getTeams: async function(accessToken) {
const client = getAuthenticatedClient(accessToken);
const events = await client
.api('/me/joinedTeams')
.version('beta')
.get();
return events;
}
this prints no results and no error. if I replace 'me/joinedTeams' to just 'me' then it returns logged in user details.
You can got a response successfully, so it seems no error with your code as you said if you call https://graph.microsoft.com/v1.0/me you can get user information.
And I tried to call this API using my account(my account hasn't joined any Teams), and got response like below, so if you got the same response as mine, perhaps you need to check if you have joined any Teams:
On the other hand, following the document, this API needs several permissions. So please obtain your access token when debug and use JWT tool to decrypt it to check if the access token have enough scope.
And I used the same request and got Teams information after adding my account to a team.

JWT Authorization with Axios and Vue.js (Header)

I'm still pretty new to web development, so I apologize in advance if the solution is obvious or my question is asked poorly.
So: I would like to use JWT to authenticate my users. I use axios, vue.js and of course JWT. I would like to access a secure route:
router.post('/secureroute', checkAuth, (req, res) => {
res.status(200).json({
message: 'all ok'
})
});
In order to do so, I use this check-auth.js:
const jwt = require('jsonwebtoken');
module.exports = (req, res, next) => {
try {
const token = req.headers.authorization.split(" ")[1];
console.log(token);
const decoded = jwt.verify(token, process.env.SECRET_KEY);
next();
} catch (error) {
return res.status(401).json({
message: 'Auth failed'
})
}
next();
}
part of my Login.vue:
methods: {
login() {
if (!this.username) this.alertUsername = true;
if (!this.password) this.alertPassword = true;
axios
.post("/user/login", {
username: this.username,
password: this.password
})
.then(res => {
localStorage.setItem("usertoken", res.data.token);
if (res.data.token) {
console.log("Success");
router.push({ name: "start" });
} else {
this.alertWrong = true;
}
this.username = "";
this.password = "";
})
.catch(err => {
console.log(err);
});
this.emitMethod();
}
Using postman with an authorization header, everything seems to work fine. But after hours of searching the Internet and trying things out, I simply do not know how to make it work with the real website. I would like to pass the JWT as an authorization-header. I know that it is possible with axios, but I really don't know how I can do so in my example here.
You've got your login flow, and you are storing the usertoken in localStorage as the usertoken key. You also verified that your requests are processed correctly if the authorization header is set.
The easiest way to work with api requests is by abstracting axios a bit more, to automatically add the authorization token, and maybe pre-process the response you get back. For example, you may want to handle some errors globally instead of on a case-by-case basis, or want to transform the request into something that is always the same.
You first want to make some abstraction that calls axios.request. You can pass it a configuration object as described here. What's most important for you right now is the headers key-value pair, but you may want to expand this in the future.
export default request (config) {
const userToken = window.localStorage.getItem('usertoken');
const requestConfig = { ...config };
if (!requestConfig.headers) {
requestConfig.headers = {};
}
if (userToken) {
requestConfig.headers.authorization = `Bearer ${userToken}`;
}
return axios.request(requestConfig);
}
Now we can expand on that:
export default post (url, data = {}, config = {}) {
return request({
...config,
method: 'POST'
url,
data
});
}
When inspecting the request in your developer console you should now see that, if the user token is correctly set in localStorage, you have an extra header in your request that is sent to the server.

Paypal IPN verification returns Invalid each time

Basically I'm getting an "Invalid" return when I try to verify a payment made using the IPN Listeners from Paypal and NodeJS, I'm sending back a urlencoded post back to paypal, for them to tell me whether it is valid or not, however it always returns Invalid.
I have a node app, and I'm using expressJS to manage all these server calls.
I already tried 2 different approaches:
app.post('/ipn', bodyParser.text({ type: 'urlencoded' }), function (req, res) {
res.sendStatus(200);
console.log('accedio al ipn');
//console.log(req.body);
var params = req.body;
ipn.verify(string, {'allow_sandbox': true}, function callback(err, msg) {
if (err) {
console.log(string);
console.error(err);
} else {
// Do stuff with original params here
if (params.payment_status == 'Completed') {
// Payment has been confirmed as completed
}
}
});
});
and
app.post('/ipn', bodyParser.text({ type: 'urlencoded' }), function (req, res) {
console.log('Received POST /');
console.log(req.body);
console.log('\n\n');
// STEP 1: read POST data
req.body = req.body || {};
res.status(200).send('OK');
res.end();
// read the IPN message sent from PayPal and prepend 'cmd=_notify-validate'
var postreq = 'cmd=_notify-validate';
for (var key in req.body) {
if (req.body.hasOwnProperty(key)) {
var value = querystring.escape(req.body[key]);
postreq = postreq + "&" + key + "=" + value;
}
}
// Step 2: POST IPN data back to PayPal to validate
console.log('Posting back to paypal');
console.log(postreq);
console.log('\n\n');
var options = {
url: 'https://www.sandbox.paypal.com/cgi-bin/webscr',
method: 'POST',
headers: {
'Connection': 'close'
},
body: postreq,
strictSSL: true,
rejectUnauthorized: false,
requestCert: true,
agent: false
};
request(options, function callback(error, response, body) {
if (!error && response.statusCode === 200) {
// inspect IPN validation result and act accordingly
console.log(body);
if (body.substring(0, 8) === 'VERIFIED') {
// The IPN is verified, process it
console.log('Verified IPN!');
console.log('\n\n');
// assign posted variables to local variables
var item_name = req.body['item_name'];
var item_number = req.body['item_number'];
var payment_status = req.body['payment_status'];
var payment_amount = req.body['mc_gross'];
var payment_currency = req.body['mc_currency'];
var txn_id = req.body['txn_id'];
var receiver_email = req.body['receiver_email'];
var payer_email = req.body['payer_email'];
//Lets check a variable
console.log("Checking variable");
console.log("payment_status:", payment_status)
console.log('\n\n');
// IPN message values depend upon the type of notification sent.
// To loop through the &_POST array and print the NV pairs to the screen:
console.log('Printing all key-value pairs...')
for (var key in req.body) {
if (req.body.hasOwnProperty(key)) {
var value = req.body[key];
console.log(key + "=" + value);
}
}
} else if (body.substring(0, 7) === 'INVALID') {
// IPN invalid, log for manual investigation
console.log('Invalid IPN!');
console.log('\n\n');
}
}
});
});
Both of them return Invalid.
First example is taken from:
https://github.com/andzdroid/paypal-ipn
Second one is taken from:
https://github.com/HenryGau/node-paypal-ipn
As far as I know, I receive a payment notification using IPN on my server, then I resend that request to Paypal so I can verify it it's valid or not, for security purposes, this is all done within the sandbox environment.
I also tried to send the request I get, but this time using POSTMAN, and it also returns Invalid, been stuck here for a while.
Note: I'm trying to use this for suscription payments, I don't know if this is relevant or not, just in case.

NodeJs - Retrieve user information from JWT token?

Node and Angular. I have a MEAN stack authentication application where I am setting a JWT token on successful login as follows, and storing it in a session in the controller. Assigning the JWT token to config.headers through service interceptor:
var token = jwt.sign({id: user._id}, secret.secretToken, { expiresIn: tokenManager.TOKEN_EXPIRATION_SEC });
return res.json({token:token});
authservice.js Interceptor(omitted requestError,response and responseError):
authServices.factory('TokenInterceptor', ['$q', '$window', '$location','AuthenticationService',function ($q, $window, $location, AuthenticationService) {
return {
request: function (config) {
config.headers = config.headers || {};
if ($window.sessionStorage.token) {
config.headers.Authorization = 'Bearer ' + $window.sessionStorage.token;
}
return config;
}
};
}]);
Now I wanted to get the logged in user details from the token, How can I do that? I tried as follows, not working. When I log the error from Users.js file it's saying "ReferenceError: headers is not defined"
authController.js:
$scope.me = function() {
UserService.me(function(res) {
$scope.myDetails = res;
}, function() {
console.log('Failed to fetch details');
$rootScope.error = 'Failed to fetch details';
})
};
authService.js:
authServices.factory('UserService',['$http', function($http) {
return {
me:function() {
return $http.get(options.api.base_url + '/me');
}
}
}]);
Users.js (Node):
exports.me = function(req,res){
if (req.headers && req.headers.authorization) {
var authorization =req.headers.authorization;
var part = authorization.split(' ');
//logic here to retrieve the user from database
}
return res.send(200);
}
Do i have to pass the token as a parameter too for retrieving the user details? Or save the user details in a separate session variable as well?
First of all, it is a good practice to use Passport middleware for user authorization handling. It takes all the dirty job of parsing your request and also provides many authorization options.
Now for your Node.js code.
You need to verify and parse the passed token with jwt methods and then find the user by id extracted from the token:
exports.me = function(req,res){
if (req.headers && req.headers.authorization) {
var authorization = req.headers.authorization.split(' ')[1],
decoded;
try {
decoded = jwt.verify(authorization, secret.secretToken);
} catch (e) {
return res.status(401).send('unauthorized');
}
var userId = decoded.id;
// Fetch the user by id
User.findOne({_id: userId}).then(function(user){
// Do something with the user
return res.send(200);
});
}
return res.send(500);
}
Find a token from request data:
const usertoken = req.headers.authorization;
const token = usertoken.split(' ');
const decoded = jwt.verify(token[1], 'secret-key');
console.log(decoded);
Your are calling the function UserService.me with two callbacks, although the function does not accept any arguments. What I think you want to do is:
$scope.me = function() {
UserService.me().then(function(res) {
$scope.myDetails = res;
}, function() {
console.log('Failed to fetch details');
$rootScope.error = 'Failed to fetch details';
});
};
Also, note that the $http methods return a response object. Make sure that what you want is not a $scope.myDetails = res.data
And in your Users.js file, you are using the variable headers.authorization directly, whereas it should be req.header.authorization:
var authorization = req.headers.authorization;
According to the documentation https://github.com/themikenicholson/passport-jwt, you could use request.user. Note, I'm supposing that you are using passport with passport-jwt.
It's possible because passport during the context of an authentication is setting the request object and populating the user property. So, just access that property. You don't need to do a middleware.
Anderson anzileiro is correct. If you return the full token in the middleware code, the request is indeed populated with the user property and you can access your profile.
passport.use(
new JWTstrategy(
{
secretOrKey: process.env.ACCESS_TOKEN_SECRET,
// jwtFromRequest: ExtractJWT.fromUrlQueryParameter('secret_token')
jwtFromRequest: ExtractJWT.fromAuthHeaderAsBearerToken()
},
async (token, done) => {
try {
return done(null, token);
} catch (error) {
done(error);
}
}
)
);
req.user will return :
{
"user": {
"username": "admin"
},
"iat": 1625920948,
"exp": 1626007348
}

Categories