Discord Bot using AWS Lambda - aws-lambda

I am trying to build a discord bot and was wonderig if i can use AWS lambda for it. So far i haven't seen someone did it already so was confuse if its possible or not. Specially when lambda's aren't active all the time.

ancient question, but this is now possible, since discord starting providing outgoing webhooks a few weeks ago
(shameless self plug) i wrote a bit of a guide here

This is now possible but following an integration approach rather than the traditional bot approach. This differs as detailed below.
The slash commands official documentation gives us this info:
Slash Commands and Interactions bring something entirely new to the table: the ability to interact with an application without needing a bot user in the guild.
You are now able to receive interaction events via your preferred URL endpoint such as an AWS Lamba function, Firebase Cloud function, Azure Cloud function, etc.
This official receiving an interaction section tells us:
In your application in the Developer Portal, there is a field on the main page called "Interactions Endpoint URL". If you want to receive Interactions via outgoing webhook, you can set your URL in this field.
It is important to remember, though, that the data sent to the endpoint URL for interactions is not the same as running a bot client, in fact they make comment on that here:
In many cases, you may still need a bot user. If you need to receive gateway events, or need to interact with other parts of our API...

In my opinion, although We can post messages by AWS Lambda using Webhook, But we can not receive and process messages using AWS Lambda.
This is because discord does not provide message posting events.

here's a minimal implementation in nodejs that will give you an acceptable Interactions Endpoint URL:
serverless.yml
service: discord
variablesResolutionMode: 20210326
frameworkVersion: '2'
provider:
name: aws
runtime: nodejs14.x
stage: whatever
region: us-east-1
lambdaHashingVersion: 20201221
iam:
role:
name: discord
# https://docs.aws.amazon.com/systems-manager/latest/userguide/sysman-paramstore-access.html
statements:
-
Effect: Allow
Action:
- 'ssm:DescribeParameters'
Resource: '*'
-
Effect: Allow
Action:
- 'ssm:GetParameter'
Resource:
- 'arn:aws:ssm:us-east-1::parameter/discord_token'
- 'arn:aws:ssm:us-east-1::parameter/discord_application_id'
- 'arn:aws:ssm:us-east-1::parameter/discord_public_key'
functions:
interactions:
handler: handler.interactions
environment:
DISCORD_TOKEN: ${ssm:/discord_token}
DISCORD_APPLICATION_ID: ${ssm:/discord_application_id}
DISCORD_PUBLIC_KEY: ${ssm:/discord_public_key}
events:
-
http:
path: interactions
method: post
cors: true
handler.js
'use strict';
const nacl = require('tweetnacl');
module.exports.interactions = async (event) => {
const verified = nacl.sign.detached.verify(
Buffer.from(event.headers['x-signature-timestamp'] + event.body),
Buffer.from(event.headers['x-signature-ed25519'], 'hex'),
Buffer.from(process.env.DISCORD_PUBLIC_KEY, 'hex')
);
const body = JSON.parse(event.body);
const response = {
body: JSON.stringify(
verified
? { type: body.type }
: { error: 'invalid request signature' },
null,
2
),
statusCode: verified
? 200
: 401
};
console.log(JSON.stringify({ event, response }, null, 2));
return response;
};

Related

Custom Authorizer for apiGatewayServiceProxies in Serverless

We are trying to create a API gateway which has Integration with SNS Topic. We are using Serverless Framework to create the Infrastructure as we need to have other Lambda functions listening to the SNS Topic. We are able to successfully create an API Gateway with backend pointing to SNS Topic using apiGatewayServiceProxies (see below)
apiGatewayServiceProxies:
- sns:
path: /sns
method: post
topicName: TopicName
cors: true
Once we deploy, we are able to submit the messages via the API Gateway. When we try to add custom Authorization to the API Gateway, the serverless deploy command is failing as the authorizerId is not accepting the values passed. This is what we have tried:
custom:
apiGatewayServiceProxies:
- sns:
path: /sns
method: post
topicName: TopicName
cors: true
authorizationType: "CUSTOM"
authorizerId: !Ref TokenAuthorizerFunction
functions:
TokenAuthorizerFunction:
handler: authorizer.handler
We followed as mentioned in the documentation here
Can someone tell me what is going wrong here?

Unpublished user in sns even if has full administrative permission, lambda out of vpc

Good night I have a serious problem when trying to publish in a sns topic, my user has full access and still not publish. I am aware that if the lambda is in a vpc then I would have problems publishing to sns, however I separated my vpc lambda from the internet access lambdas, I use invoke to access the vpc, the lambda that publishes in sns is out of vpc and I can not publish in sns. Anyone with this problem?
message:
{
"code": 1072,
"message": "User: arn:aws:iam::{accountID}:user/s3_developer is not authorized to perform: SNS:Publish on resource: arn:aws:sns:us-east-1:{accountID}:snsMailSend"
}
The user s3_developer has full access admin, but still does not post to sns.
My iam
iamRoleStatements:
- Effect: Allow
Action:
- lambda:InvokeFunction
- lambda:InvokeAsync
Resource: "*"
- Effect: Allow
Action:
- s3:GetObject
- s3:ListBucket
- s3:PutObject
Resource: "arn:aws:s3:::"
- Effect: Allow
Action:
- ses:SendEmail
- ses:SendRawEmail
Resource: "arn:aws:ses:::"
- Effect: Allow
Action:
- sns:*
Resource: "*"
SNS Trigger and create in lambda
var enviroment = "SNS_TOPIC": "snsMailSend"
sendMail:
handler: lib/controllers/smtp/send.emailSend
events:
- sns: ${self:custom.secrets.SNS_TOPIC}
The topic is successfully created, I can publish by a simple lambda, but I can not publish my application where is the lambda that has the trigger and the lambda that publishes. I don't know what's wrong, does anyone see a light?
Finally I solved, I created a specific user for SNS gave proper privileges and when instantiating sns I pass your user access and secrets, resolved. I saw that other people with similar problems hope this helps.
const aws = require('aws-sdk')
const sns = new aws.SNS({ region: process.env.REGION, accessKeyId: process.env.SNS_KEY, secretAccessKey: process.env.SNS_SECRET })

Can't get conversationUpdate activity with the Enhanced Direct Line Authentication Features

I'm trying to use the Enhanced Direct Line Authentication Features so I can get rid of the Magic Number.
I just enabled this option and added the trusted origin (https://mychatbot.azurewebsites.net/ <- Not the real one, but is stored on Azure) to the DirectLine.
Then on the code of the website I request the token:
const options = {
method: 'POST',
uri: 'https://directline.botframework.com/v3/directline/tokens/generate',
headers: {
"Authorization": "Bearer MyDirectLineSecret"
},
json: {
User: {
id: "dl_" + uuid.v4(),
name: "UserTest"
},
trustedOrigins: ["https://mychatbot.azurewebsites.net/"]
}
Then I make the request for the token:
const response = await rp(options);
const token = response.token;
Like that I have the token and when I go to my bot website (https://mychatbot.azurewebsites.net/) I don't send the updateActivity request and can't send the user the welcome message.
I don't know if I'm doing something wrong about the DirectLine configuration.
Is there anything I should change? I'm using an app service for the bot framework and inserting directly the webchat uri in the trusted origins. I don't know if I am wrong in the request of the token.
You aren't doing anything wrong. This is a known issue in the DirectLine Connector Service, and the development team is currently working to resolve the issue. Essentially, the second conversation update is not being sent because the user id in the token is causing an error. For more details, checkout this issue on Github. I'll be sure to let you know when it is resolved as well.
In the meantime, I would recommend taking a look at the Web Chat Backchannel Welcome Event sample.

How to configure my Serverless YML to use my API Gateway Authorizer?

I'm following this tutorial to use Cognito to authorize the access to my lambda function through API Gateway.
I already create my user pool with a validated user, an API Gateway authorizer and a lambda function to login and get the token ID.
When I get the token ID with my lambda function and test it in AWS console, the authorizer returns 200, so I think it is working, but when I try to send the token to my lambda function it returns "401 Unauthorized"
My YML configuration:
teste:
handler: handler.teste
memorySize: 128
events:
- http:
path: teste
method: get
authorizer:
name: api-authorizer
arn: arn:aws:cognito-idp:XXXXXXXXX:XXXXXXXXXX:userpool/XXXXXXX_XXXXXXX
type: token
EDIT
I looked at AWS Console how was my lambda function and API Gateway trigger had this details:
Autorização: COGNITO_USER_POOLS
Caminho do recurso: /teste
Endpoint de API: https://XXXXXXXXX.execute-api.XXXXXXXXX.amazonaws.com/dev/teste
Estágio: dev
Método: GET
EDIT 2
I also discovery that my serverless version is 1.47 and it looks like it is the most updated although I've read some questions on Stack where they said that serverless is in 1.5
I read this page a few times and I realize that I wasn't using the correct way, so I change my YML code to this:
functions:
teste:
handler: handler.teste
memorySize: 128
events:
- http:
path: teste
method: get
type: COGNITO_USER_POOLS
authorizer:
arn: arn:aws:cognito-idp:XXXXXXXX:XXXXXXXXX:userpool/XXXXXXXX_XXXXXXXXX
authorizerId:
Ref: api-authorizer
And I also change my authorizer source to Authorization.

Struggling with apollo-link-ws x-api-key authorization

I'm using Apollo to connect to an AWS Appsync API which is secured with an API Key. No problems with queries and mutations over http but I'm on unfamiliar territory using websockets for subscriptions.
Using apollo-link-ws I have the following, and I have no idea how to add the API Key. Can any kind soul offer advice?
const ws = new WebSocketLink({
uri: `wss://xxxxx.appsync-api.eu-west-1.amazonaws.com/graphql`,
options: {
reconnect: true
}
});
BTW I'm assuming that the url for wss is the same as for http....
apollo-ws-link does not directly work with AWS AppSync subscriptions. Take a look at the AWS Amplify GraphQL client that handles authorization with AppSync as well as subscriptions. This should get your app working with AppSync in a couple minutes.
If you want to implement your own subscriptions client, the handshake is documented within the Amplify library.
Authorization is usually based on connectionParams, but AWS decided to go different way, and they implemented it some shady way using REST and custom headers.
The problem is Websockets doesn't support custom headers. What makes it difficult to integrate with Apollo.
AppSync has much more flaws than just this one. I wouldn't recommend it for anything more ambitious than a blog or chat anyway. This article explain better some of its drawbacks.
Have you checked out the AppSync guide for "Building a JavaScript Client App": https://docs.aws.amazon.com/appsync/latest/devguide/building-a-client-app-javascript.html
With AWSAppSyncClient setting up subscriptions is effortless. It uses websockets automatically when setting up subscriptions.
I haven't even been aware of apollo-link-ws and such complexities when using AppSync subscriptions with Apollo. I only have experience of AppSync subscriptions with the React client but the plain JavaScript usage seems comparatively simple.
From the example in the guide:
const client = new AWSAppSyncClient({
url: url,
region: region,
auth: {
type: type,
credentials: credentials,
}
});
client.hydrated().then(function (client) {
//Now subscribe to results
const observable = client.subscribe({ query: subquery });
const realtimeResults = function realtimeResults(data) {
console.log('realtime data: ', data);
};
observable.subscribe({
next: realtimeResults,
complete: console.log,
error: console.log,
});
});
// Set up a subscription query
const subquery = gql(`
subscription NewPostSub {
newPost {
__typename
id
title
author
version
}
}`);
For Node.js usage, the guide also shows how to set up global.WebSocket and such dependencies in the example code.

Resources