trying to access userAttributes(email) through AdminGetUser in aws lambda - node.js

I'm trying to access user attributes in lambda function. Basically I need email of listUsersRes.Users. I'm trying through listUsersRes.Users[0].Email but it is returning undefined.
const aws = require("aws-sdk");
exports.handler = async (event, context, callback) => {
const cognitoProvider = new aws.CognitoIdentityServiceProvider({apiVersion: "2016-04-18"});
if (event.triggerSource == "PreSignUp_SignUp" ||event.triggerSource == "PreSignUp_AdminCreateUser" || event.triggerSource=="PreSignUp_ExternalProvider") {
try {
const listUserParams={UserPoolId: event.userPoolId,AttributesToGet: ["email"],Filter: `cognito:user_status= \"${"UNCONFIRMED"}\"`, Limit: 10 };
const listUsersRes = await cognitoProvider.listUsers(listUserParams).promise();
if (listUsersRes.Users.length >= 0) {
var params = {
Username: listUsersRes.Users[0].Username,
UserPoolId: event.userPoolId};
await cognitoProvider.adminGetUser(params, function(err,data){
if(err) callback(new Error(err), event);
else {
callback(new Error(data), event);
}
});
// callback(new Error(listUsersRes.Users[0].Username),event);
}else {callback(new Error("Something went wrong!"), event);}
}
catch (error) {return callback(new Error("catch error"), event);}
}
else {callback(new Error("This provider is not supported"), event);}
};
I need email of listUsers am I doing right?

Related

DynamoDB always returns "Response: null" on AWS Lambda

Consider the code :
const AWS = require('aws-sdk');
const dynamoDB = new AWS.DynamoDB({
region : 'us-east-2' ,
apiVersion: '2012-08-10'
});
exports.handler = async (event , context , callback) => {
const type = event.type;
if (type === 'all') {
// Which table we want to scan
const params = {
TableName : 'compare-yourself'
};
await dynamoDB.scan(params ,(err , data) => {
if (err) {
callback(err);
}
else{
callback(null , data);
}
});
// callback(null , "All Data");
}
else if (type === 'single') {
callback(null , "Single data");
}
else{
callback(null , "Everything else...");
}
};
When I test this piece of code on AWS Lambda with the value :
The result is always "Response: null" , even through there is data in the DynamoDB table compare-yourself.
What might be the problem here ?
Promise will solve the issue. I prefer documentclient.
const AWS = require('aws-sdk');
const documentClient = new AWS.DynamoDB.DocumentClient();
exports.handler = async (event, context, callback) => {
const type = event.type;
if (type === 'all') {
const params = {
TableName: 'compare-yourself'
};
let data = await documentClient.scan(params).promise();
callback(null, data);
} else if (type === 'single') {
callback(null, "Single data");
} else {
callback(null, "Everything else...");
}
};
The data will be an object with table values in the Items,
{
Items: [],
Count:
ScannedCount:
.....
}
try use DocumentClient();
var documentClient = new AWS.DynamoDB.DocumentClient();
const params = {
TableName : 'compare-yourself'
};
documentClient.scan(params, function(err, data) {
if (err) console.log(err);
else console.log(data);
});
Mistake:
The problem is you are doing both callback and await at the same.
Fix:
So you could put the scan function in a try block, so on error
we do callback error in the catch block and stop the function without proceeding further (return) else you will send the data.
Code:
const AWS = require('aws-sdk');
const dynamoDB = new AWS.DynamoDB({
region : 'us-east-2' ,
apiVersion: '2012-08-10'
});
exports.handler = async (event , context , callback) => {
const type = event.type;
if (type === 'all') {
// Which table we want to scan
const params = {
TableName : 'compare-yourself'
};
try {
await dynamoDB.scan(params).promise();
} catch (e) {
callback(e);
return;
}
callback(null , data);
}
else if (type === 'single') {
callback(null , "Single data");
}
else{
callback(null , "Everything else...");
}
};
Note:
Just wanted to add this, when performing scan be aware of the limits, if the limit exceeds you won't get the entire entries in the table.

How to get redis value for a given redis key using Nodejs + Redis

I am using Nodejs + redis to Set and Get key:value pairs. I have written a sample code to set a key:value pair and then fetch it using the default readme from npm redis plugin.
My goal here is to get value from the redis server using any given key. I have followed the steps as given by npm redis plugin. I am able to log it, but since the plugin is async cant figure out a way to get a synchronous client.get request.
My code is
var redis = require("redis"),
client = redis.createClient();
const bluebird = require("bluebird");
bluebird.promisifyAll(redis.RedisClient.prototype);
bluebird.promisifyAll(redis.Multi.prototype);
const redisKey = "redis-set-key";
const redisValue = "hello-world";
client.set(redisKey, redisValue);
function getData(key) {
return client.get(key, function(err, result) {
console.log("1. Get key from redis - ", result.toString());
return result.toString();
});
}
const getRedisdata = getData(redisKey);
console.log("2. getRedisdata", getRedisdata);
Result
2. getRedisdata false
1. Get key from redis - hello-world
My goal is to get the result like this
1. Get key from redis - hello-world
2. getRedisdata hello-world
Please help me resolve this.
Found a solution, here is my resolved code
const redis = require("redis");
const client = redis.createClient();
const bluebird = require("bluebird");
bluebird.promisifyAll(redis.RedisClient.prototype);
bluebird.promisifyAll(redis.Multi.prototype);
const redisKey = "redis-set-key";
const redisValue = "hello-world";
client.set(redisKey, redisValue);
async function setKey(key, value, expire = "EX", time = 300) {
return new Promise((resolve, reject) => {
return client.set(key, value, function(err, result) {
if (result === null) {
reject("set key fail promise");
} else {
resolve(result);
}
});
});
}
async function getKey(key) {
return new Promise((resolve, reject) => {
return client.getAsync(key).then(function(res) {
if (res == null) {
reject("fail promise");
} else {
resolve(res);
}
});
});
}
async function hashGetKey(hashKey, hashvalue) {
return new Promise((resolve, reject) => {
return client.hget(hashKey, hashvalue, function(err, res) {
if (res == null) {
reject("hash key fail promise");
} else {
resolve(res.toString());
}
});
});
}
async function hashGetAllKey(hashKey) {
return new Promise((resolve, reject) => {
return client.hgetall(hashKey, function(err, res) {
if (res == null) {
reject("hash key all fail promise");
} else {
resolve(res);
}
});
});
}
async function delKey(key) {
return new Promise((resolve, reject) => {
return client.del(key, function(err, result) {
if (result === null) {
reject("delete fail promise");
} else {
resolve(result);
}
});
});
}
(async () => {
// get single key value
try {
const keyData = await getKey("string key");
console.log("Single key data:-", keyData);
} catch (error) {
console.log("Single key data error:-", error);
}
// get single hash key value
try {
const hashKeyData = await hashGetKey("hashkey", "hashtest 1");
console.log("Single hash key data:-", hashKeyData);
} catch (error) {
console.log("Single hash key data error:-", error);
}
// get all hash key values
try {
const allHashKeyData = await hashGetAllKey("hashkey");
console.log("All hash key data:-", allHashKeyData);
} catch (error) {
console.log("All hash key data error:-", error);
}
// delte single key
try {
const checkDel = await delKey("XXYYZZ!!!!");
console.log("Check key delete:-", checkDel);
} catch (error) {
console.log("Check key delete error:-", error);
}
// set single key
try {
const checkSet = await setKey("XXYYZZ", "AABBCC");
console.log("Check data setkey", checkSet);
} catch (error) {
console.log("Check data setkey error", error);
}
})();
// hget hashkey "hashtest 1"
client.hset("hashkey", "hashtest 1", "some value", redis.print);
client.hset(["hashkey", "hashtest 2", "some other value"], redis.print);
Haven't you read the Redis module's readme, it provides another way to use async/await way to make the async redis get process as sync.
const { promisify } = require("util");
const getAsync = promisify(client.get).bind(client);
getAsync.then(console.log).catch(console.error);

NodeJs unable to callback AWS Secrets Manager response

I'm trying to use AWS Secrets Manager to fetch my RDS credentials,
The Secrets Manager SDK is able to get the Secret properly,
But I am unable to export it back to my calling file.
I have 2 files -
1. index.js -
var mysql = require('mysql');
var secretsManager = require('./secrets-manager');
exports.handler = (event, context, callback) => {
secretsManager.getDbCredentialFromSecretsManager(function(err,creds) {
if (err) {
console.log(err);
callback(err, null);
}
else{
console.log("Creds ", creds);
var connection = mysql.createConnection(creds);
connection.connect(function(err) {
if (err) {
console.error(err.stack);
callback(err,null);
}
else{
callback(null,connection);
}
});
}
});
}
2. secrets-manager.js -
var AWS = require('aws-sdk');
var constants = require('/opt/nodejs/utils/constants');
module.exports = {
getRDSCredsFromSM
};
function getRDSCredsFromSM (callback) {
var response = {};
let secretName = "secretId";
var client = new AWS.SecretsManager({
region: constants.aws.region
});
client.getSecretValue({SecretId: secretName}, function(err, data) {
if (err) {
console.log(err);
callback(err, null);
}
else {
if ('SecretString' in data) {
let secret = data.SecretString;
secret = JSON.parse(secret);
console.log("secret",secret);
callback(null, secret);
} else {
let buff = new Buffer(data.SecretBinary, 'base64');
let decodedBinarySecret = buff.toString('ascii');
callback(null, decodedBinarySecret);
}
}
});
}
I feel there's some mistake from me on Node side,
Which is why the callback isn't working properly,
The Lambda Timesout,
And the logs show nothing in creds variable -
console.log("Creds ", creds);
Working code -
let async = require('async');
let AWS = require('aws-sdk');
module.exports = {
getDbCredentialFromSecretsManager
};
const TAG = '[SECRETS-MANAGER-UTIL->';
function getDbCredentialFromSecretsManager (constants, callback) {
let response = {};
const METHOD_TAG = TAG + 'getDbCredentialFromSecretsManager->';
async.waterfall([
function(callback) {
let client = new AWS.SecretsManager({
region: constants.aws.region
});
client.getSecretValue({SecretId: constants.aws.sm}, function(err, data) {
if (err) {
console.log(METHOD_TAG,err);
callback(err, null);
}
else {
console.log(METHOD_TAG, 'Secrets Manager call successful');
if ('SecretString' in data) {
let secret = data.SecretString;
secret = JSON.parse(secret);
response.user = secret.username;
response.password = secret.password;
response.host = secret.host;
response.database = constants.db.database;
callback(null, response);
} else {
let buff = new Buffer(data.SecretBinary, 'base64');
let decodedBinarySecret = buff.toString('ascii');
callback(null, decodedBinarySecret);
}
}
});
}
],
function(err, response) {
if (err) {
console.log(METHOD_TAG, err);
callback(err, response);
}
else {
callback(null, response);
}
});
}

Cannot update a Firestore's document after a purchase verification using Firebase functions

I've been working on a function to verify purchase in server side. Everything works well.
Only one issue, when the purchase is valid (the response.status === 200) the console shows (success) but the document hasn't been updated.
Here is my code. Did i miss something ?
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const {google} = require('googleapis');
const publisher = google.androidpublisher('v2');
const authClient = new google.auth.JWT({
email: 'my_email',
key: 'my_key',
scopes: ['https://www.googleapis.com/auth/androidpublisher']
});
admin.initializeApp();
admin.firestore().settings({timestampsInSnapshots: true});
exports.validatePurchases = functions.firestore
.document('purchases/{channel}')
.onCreate((docSnapshot, context) => {
const purchase = docSnapshot.data();
const order_id = purchase.orderId;
const package_name = purchase.packageName;
const sku = purchase.sku;
const purchase_token = purchase.purchaseToken;
const user_id = purchase.userId;
authClient.authorize((err, result) => {
if (err) {
console.log(err);
}
publisher.purchases.subscriptions.get({
auth: authClient,
packageName: package_name,
subscriptionId: sku,
token: purchase_token
}, (err, response) => {
if (err) {
console.log(err);
}
// Result Status must be equals to 200 so that the purchase is valid
if (response.status === 200) {
console.log('success');
return admin.firestore().collection('users').doc(user_id).update({
purchaseToken: purchase_token,
isPremiumS: 'true'
});
} else {
console.log('fail');
return admin.firestore().collection('users').doc(user_id).update({
purchaseToken: purchase_token,
isPremiumS: 'false'
});
}
});
});
return null;
});
Instead of returning null, your function should return the Promise from your Firestore update() calls.
Add return in two places:
return authClient.authorize((err, result) => {...
return publisher.purchases.subscriptions.get({...
Delete return null; at the end of the function

SNS publish and Firebase Save Data does nothing in AWS Node.JS Lambda

I have been trying to use Cloud Messaging with my Lambda Function to send push notifications.
At first I tried to use SNS linked to Firebase. But calling SNS.publish does nothing... no errors, no timeouts just seems to ignore the call. Here is a snippet of where it goes wrong:
const intentName = event.request.intent.name;
// Dispatch to your skill's intent handlers
if (intentName === 'Temperature') {
getPatientTemperature(intent, context,
function (internalcontext, speechOutput) {
//sns
//var outmessage = {Display: speechOutput};
var sns = new AWS.SNS({region:'us-east-1'});
//console.log(sns);
console.log('sending push');
sns.publish({
Message: speechOutput,
TopicArn: "arn:aws:sns:us-east-1:*************:MedicalAssistantDisplayUpdates",
Subject: "TestSNS"
}, function(err, data) {
//context.callbackWaitsForEmptyEventLoop = false;
console.log("SNS here 2");
if (err) {
console.log(err.stack);
return;
}
console.log('push sent');
console.log(data);
console.log("SNS here 3");
});
context.succeed( buildResponse({}, buildSpeechletResponse("Sent",speechOutput, "no text", true)));
console.log("That's all folks");
});
} else {
throw new Error('Invalid intent');
}
It's full code:
/* eslint-disable func-names */
/* eslint-disable no-console */
//const Alexa = require('ask-sdk-core');
var mysql = require('mysql');
var AWS = require("aws-sdk");
var connection = mysql.createConnection({
host: "********************",
port: "****",
user: "*******",
password: "*****",
database: "**************"
});
//=========================================================================================================================================
//TODO: The items below this comment need your attention.
//=========================================================================================================================================
const SKILL_NAME = 'Medical Assistant';
const GET_TEMPERATURE_MESSAGE = '\'s temperature is ';
const HELP_MESSAGE = 'You can say tell me the latest tempearture of patient patient ID, or, you can say exit... What can I help you with?';
const HELP_REPROMPT = 'What can I help you with?';
const FALLBACK_MESSAGE = 'The Medical Assistant can\'t help you with that. It can help you retrieve a patient\'s tempearture. What can I help you with?';
const FALLBACK_REPROMPT = 'What can I help you with?';
const STOP_MESSAGE = 'Goodbye!';
// --------------- Helpers that build all of the responses -----------------------
function buildSpeechletResponse(title, output, repromptText, shouldEndSession) {
return {
outputSpeech: {
type: 'PlainText',
text: output,
},
card: {
type: 'Simple',
title: `${title}`,
content: `${output}`,
},
reprompt: {
outputSpeech: {
type: 'PlainText',
text: repromptText,
},
},
shouldEndSession,
};
}
function buildResponse(sessionAttributes, speechletResponse) {
return {
version: '1.0',
sessionAttributes,
response: speechletResponse,
};
}
function getPatientTemperature(intent, context, callback) {
const cardTitle = intent.name;
const PatientID = intent.slots.PatientID.value;
console.log(PatientID);
let repromptText = '';
let sessionAttributes = {};
const shouldEndSession = false;
let speechOutput = '';
console.log('Then run MySQL code:');
//connection.connect(function(err) {
console.log('Inside connection.connect() callback');
//context.callbackWaitsForEmptyEventLoop = false;
//if (!err) {
console.log("Database is connected ... ");
connection.query("SELECT Temperature, Patient_Name FROM (SELECT * FROM (SELECT c.Temperature, p.Patient_Name, c.Recorded_Time FROM ConsultationRecords c, Patients p WHERE (c.Patient_ID = p.Patient_ID) AND c.Patient_ID = '"+ PatientID +"' AND c.Temperature IS NOT NULL)AS Alias ORDER BY Recorded_Time DESC LIMIT 1) AS RequiredTemp",
function(err, result) {
//connection.end();
console.log("Inside connection.query() callback")
if (!err) {
console.log("Query Successful! Ending Connection.");
//connection.end();
if (result.length > 0) {
if(result[0].Temperature == 'null'){
}
else{
speechOutput = result[0].Patient_Name+"'s temperature is "+result[0].Temperature;
console.log("Returning Response");
}
}
else{
speechOutput = "Patient ID not found in records";
console.log("Returning invalid ID Response");
}
callback(context, speechOutput);
} else {
console.log("Query error!");
}
});
// } else {
// console.log("Error connecting database ..." + err.message);
// connection.end();
// }
console.log("here end");
// });
}
function getWelcomeResponse(context) {
// If we wanted to initialize the session to have some attributes we could add those here.
const sessionAttributes = {};
const cardTitle = 'Welcome';
const speechOutput = 'Welcome to Medical Assistant. ' +
'You can ask for Patient information like Temperature';
// If the user either does not reply to the welcome message or says something that is not
// understood, they will be prompted again with this text.
const repromptText = 'For example, say: what is the latest temparature of patient 1.';
const shouldEndSession = false;
console.log(`Send Welcome Response`);
context.succeed(buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession));
}
exports.handler = (event, context) => {
try {
if (event.session.new) {
// New Session
console.log("NEW SESSION");
}
// Fix for hardcoded context from simulator
//if(event.context && event.context.System.application.applicationId == 'applicationId'){
// event.context.System.application.applicationId = event.session.application.applicationId;
//}
switch (event.request.type) {
case "LaunchRequest":
console.log(`Launch Request`);
getWelcomeResponse(context);
console.log(`End Launch`);
break;
case "IntentRequest":
// Intent Request
console.log(`Intent Request`);
const intent = event.request.intent;
const intentName = event.request.intent.name;
// Dispatch to your skill's intent handlers
if (intentName === 'Temperature') {
getPatientTemperature(intent, context,
function (internalcontext, speechOutput) {
//sns
//var outmessage = {Display: speechOutput};
var sns = new AWS.SNS({region:'us-east-1'});
//console.log(sns);
console.log('sending push');
sns.publish({
Message: speechOutput,
TopicArn: "arn:aws:sns:us-east-1:**********:MedicalAssistantDisplayUpdates",
Subject: "TestSNS"
}, function(err, data) {
//context.callbackWaitsForEmptyEventLoop = false;
console.log("SNS here 2");
if (err) {
console.log(err.stack);
return;
}
console.log('push sent');
console.log(data);
console.log("SNS here 3");
});
context.succeed( buildResponse({}, buildSpeechletResponse("Sent",speechOutput, "no text", true)));
console.log("That's all folks");
});
} else {
throw new Error('Invalid intent');
}
break;
case "SessionEndedRequest":
// Session Ended Request
console.log(`SESSION ENDED REQUEST`);
break;
default:
context.fail(`INVALID REQUEST TYPE: ${event.request.type}`);
}
} catch (error) {
context.fail(`Exceptiodn: ${error}`)
}
};
After console.log('sending push'); it correctly runs context.succeed and the final console.log.
For my second attempt I tried to use the Firebase Admin SDK to update the firebase database (figuring I can store my messages there and then trigger a push notification from firebase when an insertion is made). I created a whole new Lambda function to test that and again.. just seems to ignore usersRef.set call. Here is the full code for that function:
var admin = require("firebase-admin");
var serviceAccount = require("medicalassistantviewer-firebase-adminsdk-7xw02-266915e453.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://****************.firebaseio.com"
});
// As an admin, the app has access to read and write all data, regardless of Security Rules
var db = admin.database();
var ref = db.ref();
var usersRef = ref.child("Messages");
exports.handler = (event, context) => {
console.log("Let's start");
context.succeed(usersRef.set({
message2: {
Message: "testing again",
Token: "200"
},
message3: {
Message: "and again",
Token: "300"
}
}, function(err, data) {
//context.callbackWaitsForEmptyEventLoop = false;
console.log("messages not sent");
if (err) {
console.log(err.stack);
return;
}
console.log('messages sent');
console.log(data);
console.log("here");
}));
};

Resources