Redirect link to distribution slack app - aws-lambda

I'm trying to redirect URL to distribute (OAuth 2.0)my slack app with API gateway and lambda function (AWS) but I can't realize how to get the code.
the event that returns is null.
My lambda code :
// Lambda handler
exports.handler = (event, context, callback) => {
var messageTest = {
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
code: event.code
};
var queryTest = qs.stringify(messageTest);
https.get(`https://slack.com/api/oauth.access?${queryTest}`, (res, err) => {
console.log("statusCode: ", res.statusCode);
console.log("headers: ", res.headers);
var data = [];
res.on('data', function(chunk) {
data.push(chunk);
});
res.on('end', function() {
var result = JSON.parse(data.join(''))
console.log(result);
});
});
callback(null);
};
My redirect URL is the lambda URL.
The event that i get is null.
How can i get the "code" from the oAuth 2.0?

Assuming you are using Lambda Proxy integration (and therefore you don't use a Body Mapping Template), the JSON payload that you send to your API Gateway will be received by your Lambda as a stringified JSON in event.body.
So, you'll need to parse that first and you can get your code.
const body = JSON.parse(event.body)
const code = body.code
Reference: Input Format of a Lambda Function for Proxy Integration

Related

Receive & Respond to Twilio Text Message with Node js express graphql

I followed the Twilio instructions to setup receive & respond to a text message as in the URL below which uses a Rest Post. It works. Great.
app.post('/sms', (req, res) => {
// Start our TwiML response.
const twiml = new MessagingResponse();
// Add a text message.
const msg = twiml.message('Check out this sweet owl!');
// Add a picture message.
msg.media('https://demo.twilio.com/owl.png');
res.writeHead(200, {'Content-Type': 'text/xml'});
res.end(twiml.toString());
});
I then wanted to convert the REST POST to a graphql POST to be consistent with my code base. I set it up, and my graphql POST responds with the following format which is not xml (which I believe Twilio requires) but json as per graphql. Thus, I can see the response move through the system but Twilio registers an error. If I'm correct, is there a way for Twilio to process the graphql json response or for me to adjust graphql to return xml rather than json (as below)?
My latest graphql attempt wraps the rest post in a graphql query as such.
sms: async () => {
// console.log(request, response);
const { MessagingResponse } = require("twilio").twiml;
const twiml = new MessagingResponse();
twiml.message("The Robots are coming! Head for the hills!");
let test = "";
return axios({
method: "post",
url: "https://2b52-98-38-82-19.ngrok.io/sms",
responseType: 'text/xml'
})
.then(res => test = res.data)
// .then(function (response) {
// console.log('axios response =', response);
// return twiml.toString();
// })
.catch(function (error) {
console.log(error);
});
}
}
returning the following via Apollo Sandbox and/or insomnia.
{
"data": {
"sms": "<?xml version="1.0" encoding="UTF-8"?><Response><Message>The Robots are coming! Head for the hills POST POST!</Message></Response>"
}
}

Nextjs api resolving before form.parse completes so i cant send response back

I am trying to send an image to Next.js api and then use that image to upload to db.
I am using :
const body = new FormData();
body.append("file", prewiedPP);
const response = await fetch("/api/send-pp-to-server", {
method: "POST",
body ,
headers: {
iext: iExt,
name: cCtx.userDetail ,
},
});
Then in the api :
async function handler(req, res) {
if (req.method === "POST") {
console.log("In");
const form = new formidable.IncomingForm();
form.parse(req,
async (err, fields, files) =>
{
// console.log(req.headers.iext);
// console.log(req.headers.name);
const fdata = fs.readFileSync(files.file.filepath);
await delUserPP(req.headers.name , req.headers.iext);
await setUserPP(
fdata ,
req.headers.name ,
req.headers.iext ,
files.file.mimetype
);
fs.unlinkSync(files.file.filepath);
return;
});
console.log("out");
}
}
export default handler;
The callback function in the from.parse happens after the handler already resolved.
Is there anyway to make the api call only resolve after the setUserPP function is done?
I want to send a response back to the client but the api script finishes to "fast" and before the callback in form.parse runs.
Thanks

Fitbit URL callback giving a response of NULL

I'm having trouble getting a response from a callback uri and I would really appreciate any help you could give me.
I am trying to use the Fitbit API which requires you to use a callback url to get an Auth Code.
Workflow:
1. Go to Fitbit url to get user to allow the app access to their personal data.
2. User agrees to the conditions
3. User gets redirected to my API
4. The API returns the code from (Code is located in URL and I can access it)
5. I console.log the code out to verify it
6. API returns the code
7. I work with code then exchanging it for an access token.
The problem is that I don't return the code (Or anything )when I return to the app even though I can console.log it on the API. The response I get is NULL
Here is the URL:
url = "https://www.fitbit.com/oauth2/authorize?response_type=code&client_id=CLIENT_ID&redirect_uri=https://REDIRECT_URL&scope=activity%20heartrate%20location%20nutrition%20profile%20settings%20sleep%20social%20weight&expires_in=604800";
I then open the URL in the InAPPBrowser successfully:
if (url !== "") {
const canOpen = await Linking.canOpenURL(url)
if (canOpen) {
try {
const isAvailable = await InAppBrowser.isAvailable()
if (isAvailable) {
const result =InAppBrowser.open(url, {
// iOS Properties
dismissButtonStyle: 'done',
preferredBarTintColor: 'gray',
preferredControlTintColor: 'white',
// Android Properties
showTitle: true,
toolbarColor: '#6200EE',
secondaryToolbarColor: 'black',
enableDefaultShare: true,
}).then((result) => {
console.log("Response:",JSON.stringify(result))
Linking.getInitialURL().then(url => {
console.log("Tests: ",url)
this._setTracker(url as string);
});
})
} else Linking.openURL(url)
} catch (error) {
console.log("Error: ",error)
}
}
}
From here the URL opens successfully.
Here is the API now which is done in Typescript on AWS serverless and Lambda
export const handler: APIGatewayProxyHandler = async (event, _context, callback) =>{
let provider = event.path
//prints code
let x = event.queryStringParameters
console.log("Code: ",x)
const response = {
statusCode: 200,
body: "Success"
};
return response;
}
Please let me know if further detail is required?
Thank you!
Right so it turns out what I was doing was correct apart from the response should have been 301 which is a redirect response.
const response= {
statusCode: 301,
headers: {
"location": `app://CALLBACK RESPONSE ADDRESS?type=${provider}`
},
body: "Boom"
}

Sending message from Cognito triggers

I want to restrict user sign-ins from Cognito hosted UI. I can see there are triggers in which we can attach lambda, but whenever I change event object inside of lambda, instead of getting my custom message User exceeded limits, I get unrecognizable lambda output error.
Can anyone help me in this or is there any other way to achieve this functionality?
Now,I'm getting this
with this code :
exports.handler = (event, context, callback) => {
if (true) {
var error = new Error("Cannot signin because your signin count is 5");
// Return error to Amazon Cognito
callback(error, event);
}
// Return to Amazon Cognito
callback(null, event);
};
But,I don't want prefix PreAuthentication failed with error,I just want to display my message.
Any help is appreciated.
Currently, there is no way to stop Cognito from adding the prefix because the form is a hosted web UI.
If this is a hard requirement, the workaround is to create your own login form and use the aws-cognito-sdk
Once you make the call to cognitoUser.authenticateUser in the code below the Pre authentication trigger will fire the Lambda function and you will need to handle the error and parse it to remove the unwanted prefix.
Hope this Helps
aws Examples: Using the JavaScript SDK
var authenticationData = {
Username : 'username',
Password : 'password',
};
var authenticationDetails = new AmazonCognitoIdentity.AuthenticationDetails(authenticationData);
var poolData = { UserPoolId : 'us-east-1_TcoKGbf7n',
ClientId : '4pe2usejqcdmhi0a25jp4b5sh3'
};
var userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
var userData = {
Username : 'username',
Pool : userPool
};
var cognitoUser = new AmazonCognitoIdentity.CognitoUser(userData);
cognitoUser.authenticateUser(authenticationDetails, {
onSuccess: function (result) {
var accessToken = result.getAccessToken().getJwtToken();
/* Use the idToken for Logins Map when Federating User Pools with identity pools or when passing through an Authorization Header to an API Gateway Authorizer*/
var idToken = result.idToken.jwtToken;
},
//Your message from the Lambda will return here, you will need to parse the err to remove the unwanted prefix*
onFailure: function(err) {
alert(err);
},
});

How to send message back to device from Lambda function?

Is there any way we can send a message to a device from Lambda function which is invoked by Alexa Skill. The message contains some values collected by Lambda function.
So basically I want to do this:
Device ---> Voice command ---> Alexa Skill --(Trigger)--> Lambda function
Lambda function(collect values) ---- message ---> Device
Is there any example in Java?
Thanks for any pointer/help.
-James
Invoke Alexa device from lambda function is a very similar question, with the answer: "it's not possible YET"
I will elaborate. You can send notifications to all users of a skill such as a new feature, however, you cannot send a notification to a specific user that invokes a function.
To send notifications to all users of an Alexa skill who have notifications enabled, see this design.
Reference this thread for more information on the limitations of sending a notification to a specific user.
What you are asking can be done.
First the voice command does not come from a human from your diagram.
A device talks to Alexa. Alexa invokes or triggers Lambda. Lambda function messages device.
The function inside Lambda is http or https. If your device can handle https or TLS encryption then good. But most of the device are small and have limited computing power, so you will end up using http. As of now 2020, AWS allows http, but a year from now it requires you to use https or TLS 1.3 due to federal regulations. But we don't know until it happens.
Below is a sample of Lambda http post in NodeJS. The trigger data comes in request. So you should know what JSON will come in and extract your data from JSON using the if statement.
NodeJS website has good examples for http.
Now your device is the server. It has to anticipate the Lambda request and process it and reply to Lambda if needed.
Now your device talks and receives information.
const http = require('http');
exports.handler = async (request, context) => {
if (request.directive.header.namespace === 'FromAlexaSkill') {
httpost("This is your data to device", "192.168.1.2");
}
//**********************************************
let httpPost =async (postData, servername) => {
let dataString = '';
const response = await new Promise((resolve, reject) => {
const options = {
hostname: servername,
port: 1777,
path: '/dim',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(postData)
}
};
const req = http.request(options, (res) =>
{
res.setEncoding('utf8');
res.on('data', chunk => {
dataString += chunk;
});
res.on('end', () => {
resolve({
"body":dataString
});
});
});//http.request
req.on('error', (e) => {
console.error("problem with request: "+e.message);
reject({
statusCode: 500,
body: 'Something went wrong!'
});
});
// Write data to request body
req.write(postData);
req.end();
}); //Promise
return response;
};//httpPost
}

Resources