Lambda, updating Cognito custom user attributes doesn't do anything - node.js

iv been setting up a lambda instance, it grabs data from a few different services and then its meant to update a custom Cognito attribute for that user, that works correctly and i get the return response "{}" along and no errors so im assuming that means its working correctly, however when i check the users attributes its not returning anything?
i have triple checked that the app clients have read and write permissions, so i have no idea whats happening, everything, as far as i can tell, is working, just that the attribute isnt changing.
return new Promise((resolve, reject) => {
console.log("TestInside");
// setTimeout(function() {
console.log("TimeoutFunction");
var cognitoidentityserviceprovider = new AWS.CognitoIdentityServiceProvider();
var params = {
UserAttributes: [
{
Name: 'locale',
Value: UserFarms
},
],
UserPoolId: 'UserPoolID',
Username: UserName
};
console.log("Executing call");
const cognitoD = cognitoidentityserviceprovider.adminUpdateUserAttributes(params, function(err, data) {
if (err) {
console.log(err, err.stack); // an error occurred
//passon = err.message;
resolve('Error');
}
else {
// cognitodata = data;
console.log('Returned positive cognito admin update');
//UserName = data.Username;
//passon = data;
console.log(data);
resolve(data);
}
}).promise();
whats wrong, am i missing somthing really simple?

Related

function exits when passing data to aws cognito after reading file from s3 in aws lambda in nodejs

i am new to this , i am having problem , i have to create almost 200 users in cognito after reading data from csv file which is located in S3 bucket
the problem is , if a user already exists in Cognito , my code stop executing and give me an error "An account with the given email already exists." is there a way that i can pass the whole data. if there is user already in the cognito with the same email, it skips that user and checks for the new user data , and at the end which users are already exists in cognito .this the function to create user in cognito
here is the function for creating the cognito user
function RegisterUser(data2) {
console.log(data2[1])
for(let i=0;i<=data2.length;i++){
var attributeList = [];
var cognitoUser;
attributeList.push(new AmazonCognitoIdentity.CognitoUserAttribute({ Name: "name", Value: data2[i][0]}));
attributeList.push(new AmazonCognitoIdentity.CognitoUserAttribute({ Name: "email", Value: data2[i][1] }));
try{
return new Promise((resolve, reject) => {
userPool.signUp(data2[i][1], data2[i][2], attributeList, null, (err, result) => {
if (err) {
console.log(err.message);
reject(err);
return;
}
cognitoUser = result.user;
resolve(cognitoUser);
});
});
}catch(err){
return{
success:false,
message:err
}
}
}
}
here is the lambda handler
exports.handler = async (event, context) => {
try {
// Converted it to async/await syntax just to simplify.
const data = await S3.getObject({Bucket: 'user-data-file', Key: 'SampleCSVFile_2kb.csv'}).promise();
var data1 = Buffer.from(data.Body).toString();
var data2 = data1.split("\r\n"); // SPLIT ROWS
for (let i in data2) { // SPLIT COLUMNS
data2[i] = data2[i].split(",");
}
const userPoolResponse = await RegisterUser(data2);
}
catch (err) {
return {
statusCode: err.statusCode || 400,
body: err.message || JSON.stringify(err.message)
}
}
}
A quick google search brought this up: How to check Email Already exists in AWS Cognito?
Which sure thats Front end but your use case seem to be a quick once in a while run script, not a regular use User System - in which case, this is basic programing 101 to solve. You put another try catch around your call to register the user. You check the exception thrown, and if its 'already registered' you pass and continue in the loop without interruption. The above link can give you some idea of what to look for to determine if it is that exception or not.

How to send a NODE.JS post request from an Angular Project?

I have a NODE.JS api using expressjs that connects to an SQL Server, and I want to use it in an angular project. I make use two files, a route file and a controllers file. My route file is as follows:
module.exports = (app) => {
const UsrContrllr = require('../Controllers/users.controllers');
//1. GET ALL USERS
app.get('/api/users', UsrContrllr.func1);
//2. POST NEW USER
app.post('/api/user/new', UsrContrllr.func2);
};
And my controllers file is given below:
const mssql = require('mssql');
exports.func1 = (req, res) =>
{
// Validate request
console.log(`Fetching RESPONSE`);
// create Request object
var request = new mssql.Request();
// query to the database and get the records
const queryStr = `SELECT * FROM USERS`;
request.query(queryStr, function (err, recordset) {
if (err) console.log(err)
else {
if (recordset.recordset.toString() === '') {
res.send('Oops!!! Required data not found...');
}
else {
// send records as a response
res.send(recordset);
}
};
});
};
exports.func2 = (req, res) =>
{
// Validate request
console.log(`INSERTING RECORD ${req}`);
// create Request object
var request = new mssql.Request();
// query to the database and get the records
const queryStr = `INSERT INTO GDUSERS (USERCODE, PASSWORD, LANGUAGE, USERCLASS, FIRSTNAME, LASTNAME, CONTACTNO) VALUES ('${req.body.usercode}', '${req.body.password}', 'EN', '0', '${req.body.firstname}', '${req.body.lastname}', '${req.body.contactno}');`;
request.query(queryStr, function (err, recordset) {
if (err) console.log(err)
else {
if (recordset.recordset.toString() == '') {
res.send('Oops!!! Required data not found...');
}
else {
// Send records as response
res.send(recordset);
}
};
});
};
The GET request works well, but when I try to run the POST request directly from the angular application, I get an error stating
Cannot GET URL/api/user/new
The angular code in my angular project is:
signup() {
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
console.log(this.user); //User details come from a form
this.http.post(“URL", this.user, options)
.subscribe(
(err) => {
if(err) console.log(err);
console.log("Success");
});
}
I’m not sure whether the angular code I’m using, is right or not, and I don’t know where I’m going wrong. How does one exactly send a http POST request from an Angular project?
this i the way i handled my user signup with http.post calls. my approach is slightly different when signing up user because i am using a promise instead of observable (which i normally use for my servicecalls). but i will show you both ways.
createUser(user: User): Promise < string > {
const promise = new Promise < string > ((resolve, reject) => {
const userForPost = this.createUserForPost(user);
this.http.post(environment.backendUrl + '/api/user/signup', userForPost, this.config).toPromise < HttpConfig > ()
.then(createdUser => {
}).catch(error => {
console.log(error);
});
});
return promise;
}
here another example with an observable
createForumPost(forumPost: ForumPost) {
this.http.post < { message: string, forumPostId: string } > (environment.backendUrl + '/api/forumPosts', forumPost).subscribe((responseData) => {
const id = responseData.forumPostId;
forumPost.id = id;
});
}
i defined my URL somewhere else and then just use the environment.backedUrl + 'path' to define my path (the same as the path in your backend controller)
this is one of my first answers here on SO. i am sry if it is a bit messy
i hope i was able to help with my examples :)

Getting Error Like RequestsLimitError: You just made too many request to instagram API in node js?

I am work with isntagram api in node js. i have one array and in the array store above 20k up instagram id. and then i am do foreach on that array and one by one take instagram id and go for the take bio but that time i am getting error like this RequestsLimitError: You just made too many request to instagram API. i am try every 5 call after set time out also but still i am getting same error so how can resolved this error any one know how can fix it then please let me know.
Here this is my code =>
var InstaId = ["12345687",20k more id store here in the array]
var changesessionFlage = 0;
async.each(InstaId, function (id, callback) {
async.parallel([
function (cb) {
if (id) {
setTimeout(function () {
Client.Account.getById(sess, id).then(function (bio) {
console.log("changesessionFlage" + changesessionFlage);
changesessionFlage++
//console.log("bio : ", bio._params); // here i am getting bio one by one user
if (changesessionFlage == 6) {
changesessionFlage = 0;
}
cb(null, bio._params);
})
.catch(function (err) {
console.log("get boi: ", err)
cb(null, bio._params);
})
}, (changesessionFlage == 5) ? 10000 : 0)
}
}
], function (err, results) {
if (err) {
console.log(err);
return;
}
Result = results
callback();
});
}, function (err) {
if (err) {
console.log(err);
return;
}
else {
console.log("Result=>", Result)
if (Result) {
console.log("Result[0]=>", Result[0])
var ws = XLSX.utils.json_to_sheet(Result[0]);
var wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, "People");
var wbout = XLSX.write(wb, { bookType: 'xlsx', type: 'binary' });
res.end(wbout, 'binary');
}
}
});
any one know how can fix this issue then please help me.
Your setTimeout is use incorrectly, all API calls are made at once after 10000 delay.
Since this is a one time job, just split the 20K usernames to 4K batches and execute them every hour. This way you will be under the 5k/hr API limit

Is it OK to generate session secret(or any other secret keys) and store it in host server?

I'm testing Google OAuth2.0 on node.js + express and using express-session for managing session, and I came across that I need Secret Key for my session manager.
So I did some research and found a post, which has some nice suggestions. But it seems to require some workarounds, like setting secret key as environment variable or keeping it in configuration file.
Using the former, I need to enter environment variables every time I redeploy sever.
Using the latter exposes my secret key to SCM.
So I decided to generate random string and store it in the host file system. It seems to solve all the problems I introduced above, but I'm noob to web development so I'm not sure whether this is legit.
Is there any cons or exploit to this method?
Below is my sessionSecret.js file:
var crypto = require('crypto');
var fs = require('fs');
var filePath = '/home/ubuntu/results.txt';
function readSecretKey() {
return new Promise(function(resolve, reject) {
fs.readFile(filePath, 'utf8', function(err, key) {
if (err) {
reject(err);
} else {
resolve(key);
}
});
});
}
function writeSecretKey(key) {
return new Promise(function(resolve, reject) {
fs.writeFile(filePath, key, function(err) {
if (err) {
reject(err);
} else {
resolve(key);
}
});
});
}
function generateRandomString() {
return new Promise(function(resolve, reject) {
crypto.randomBytes(48, function(err, buf) {
if (err) {
reject(err);
} else {
resolve(buf.toString('hex'));
}
})
});
}
module.exports.getOrCreate = function() {
return new Promise(function(resolve, reject) {
readSecretKey()
.then(function(key) {
console.log("Key exists: " + key);
resolve(key);
}, function() {
console.log("Key does not exists. Generating...");
return generateRandomString();
})
.then(function(key) {
if (key) {
console.log("Key generated: " + key);
return writeSecretKey(key);
}
}).then(function(key) {
if (key) {
resolve(key);
}
}, function(err) {
reject(err);
});
});
};
Your intuition is correct.
Passing secrets in as an environment variable is just moving the problem outside the app. You have to have them somewhere anyway.
Passing them as an argument is less secure than a file, because any user on the server can ps aux and see them.
The only thing you did wrong in my opinion is overcomplicating it. I recommend dropping most of the code from the sessionSecret.js and instead of generating it on the fly, just get it from the config file. Shutdown the app if config file is not there.
Don't store the secrets in repository/SCM
I put my secrets in a special folder in /etc/ of the server. If someone gets access to that, stealing sessions is the least they can do.
Storing the session in an environment variable is considered best practice.
See 12factor.net/config

How should I create custom modules that require a mongodb connection?

I'm working on a web app with nodejs, express, and mongodb.
In my 'main' file where I listed for API calls, I include a Users class that has methods like Users.authenticate(userObject, callback), and Users.getById(userId, callback).
Sorry for this long code snippet. It's just a snippet of my users class.
function Users (db) {
if (!db) {
return {'message': 'creating an instance of Users requires a database'}
} else {
this.db = db;
return this;
}
}
Users.prototype.authenticate = function (user, callback) {
if (!user.username) {
return {'message': 'Users.authenticate(user, callback) requires user.username'};
} else if (!user.password) {
return {'message': 'Users.authenticate(user, callback) requires user.password'};
} else if (!callback) {
return {'message': 'Users.authenticate(user, callback) requires callback(err, user)'};
}
this.db.collection('users', function (err, collection) {
if (err) {return {'message': 'could not open users collection'}};
/* query for the user argument */
collection.findOne(user, function (err, doc) {
if (!err) {
if (!doc) {
callback({'message': 'user does not exist'}, null);
} else {
callback(null, doc);
}
} else {
callback({'message': 'error finding user'}, null);
}
});
});
};
exports.Users = Users;
That's it
I pass an open DB connection to my Users class, and make a call like the following:
var server = new mongo.Server('localhost', '27017', {auto_reconnect: true});
var db = new mongo.Db('supportdash', server, {"fsync": true});
// open connection to be, init users
db.open(function (err, db) {
var users = new Users(db);
users.authenticate({"username": "admin", "password": "password"}, function (err, user) {
// do something with the error, or user object
});
});
Now for my questions
Should I be passing an open db connection, or should I be passing the info needed (localhost, port, database name) for the Users class to manage its own connection?
I tried to set up testing with jasmine-node, but I ended up with a lot of problems with async database calls. I wanted to add a user, then test that Users.authenticate was working. I used Jasmines runs() and waitsfor() async helpers, but I could not get it to work. I then ran into an issue that took me a while to debug (with a different class), and testing would have saved me a lot of time. Any advice on how I would test my classes that interact with a mongodb database?

Resources