hangouts-chat: hangouts chat bot unable to post messages to a Bot implementation https endpoint - chat

I have developed a HTTPS Synchronous end point that responds to POST messages and configured the URL as "Bot URL" under Chat bot configuration for Hangouts Chat. It is deployed to an EC2 in amazon aws and added a route53 entry for the URL: https://mychatbot-implementation which redirects HTTPS POSTs to my ec2.
However, chat bot is not posting any messages to the https end point and there are no errors logged.
Link to screenshot of chat-bot configuration
Chat Bot Implementation Code Here:
from flask import Flask, request, json, render_template, make_response
app = Flask(__name__)
#app.route('/', methods=['POST'])
def on_event():
event = request.get_json()
resp = None
if event['type'] == 'REMOVED_FROM_SPACE':
logging.info('Bot removed from space...')
if event['type'] == 'ADDED_TO_SPACE':
text = 'Thanks for adding me to "%s"!' % event['space']['displayName']
elif event['type'] == 'MESSAGE':
text = 'You said: `%s`' % event['message']['text']
else:
return
return json.jsonify({'text': text})
if __name__ == '__main__':
app.run(port=8080, ssl_context='adhoc', debug=True, host='my host ip address')
Could someone please advise on the next steps?

Unfortunately, mychatbot-implementation isn't a valid Internet TLD, so Route53 will never be able to route your request (in fact, it won't get it). You have 2 issues to be concerned with (bot implementation, user-reachability) and need to tackle them separately (divide-n-conquer) rather than trying to solve everything at once.
I suggest that to test your bot implementation, you keep your bot running on EC2 and get a reachable IP address (w.x.y.z) to your instance (plus port#) and change your configuration to point to that, i.e., https://w.x.y.z:8080/ and see if the Hangouts Chat service can reach your bot. Once you get this working and your bot debugged, then you can worry about getting a TLD and registering with DNS.

Related

Hosting a Telethon User BOT on google-app-engine

I am trying to deploy a simple user bot on Google App Engine Flexible Environment running python3.7, but I get the following error. Can anyone help me with suggestions of solving this?
"File "/env/lib/python3.7/site-packages/telethon/client/auth.py", line 20, in phone: typing.Callable[[], str] = lambda: input('Please enter your phone (or bot token): '), EOFError: EOF when reading a line"
Thank you for your time
Telethon (obviously) requires you to login and make a normal user session on your account, which natively requires you to input your number when asked and enter the code received but since Google App engine doesn't allow input as #Sashidhar mentioned, depending on your userbot implementation, you can try using the userbot.session method for authentication, it can be generated locally and placed in the Google App Engine.
I try to use python on app engine to call telethon functions, upon deploy the app. I receive the Internal Server Error from browser.
I am seeing you are success on this road, would you mind shine a light on this to help me starting up, such as how to configue the app.yaml, main.py, requirements.txt , .... or any proper arrangement of librarys to make this work.
much much thanks in advance.
following is my main.py which raised server internal error on brows, the problem does not happen if this first telethon related line is remarked:
client = TelegramClient(phone, api_id, api_hash)
main.py
--------
from flask import Flask, request
import datetime
import time
import asyncio
from telethon import TelegramClient, events, sync
app = Flask(__name__)
api_id = xxxxxxxx
api_hash = 'xxxxxxxxxxxxxxxxxxxxxxxx'
phone = '+xxxxxxxxxxxx'
#app.route('/', methods=['GET'])
def hello():
reqaction = request.args.get('action', 'connect')
client = TelegramClient(phone, api_id, api_hash)
if __name__ == '__main__':
app.run(host='localhost', port=8080, debug=True)
would you mind shine a light on this to help me starting up, much thanks
I am now able to host my user BOT on GAE using the session string login method.
https://docs.telethon.dev/en/latest/concepts/sessions.html#string-sessions

Stop Facebook/Other Apps from crawling my web application via private sharelink

Edit: The suggested answer does not work as the robots are not just randomly crawling from my index, they are visiting a specific link when it is entered in a FB message.
I've created a basic chat application in Flask on App Engine. It allows the user to invite others by adding their ID or by giving them a private sharelink that auto-adds who ever goes to it (similar to youtube or google drive).
A serious flaw I have found is that if a user posts the link into a facebook message, Facebook will crawl/visit the link and by design of my system add them as a user to the conversation. All of a sudden you'll see 3 random users join the conversation.
My chat system is completely anonymous and designed to be temporary so theres no login or authentication other than a unique key for each user saved in their session.
So Facebook bots visit the link, get assigned an ID and get authenticated into the conversation because they used the users share-link, is there a way I can stop this via either Flask/Python or App Engine? Could I IP ban facebook?
Some code for the sake of code, does this for every new visitor:
def requires_session(f):
#wraps(f)
def decorated(*args, **kwargs):
if 'profile' not in session:
user_ref = fs_database.collection('users').document()
data = {
'id': user_ref.id,
'date': datetime.now(timezone.utc)
}
# add the user to the database
user_ref.set(data)
# save their id to their session
session['profile'] = data.get('id')
# create a hash for later on to create a sharelink
session['share'] = hashlib.sha256(data.get('id').encode('utf-8')).hexdigest()
return f(*args, **kwargs)
return decorated
I could maybe add a check first if Facebook-bot: return False
For your case I would say that you can avoid that either on your side or on Google Cloud Platform side. To be more precise, you can reject some connections in your code or you can set firewall rules to your App Engine instance to reject connections coming from certain IPs. In the public documentation you can find more information about firewall rules when using GAE:
Using flex environment.
Using standard environment.
Code-wise you can check at this github repo which is addresses the issue of blocking certain IPs to your Flask app.
The last possible option is authentication, but as the chat is anonymous I guess that's not the solution you are looking for.
The accepted answer lead me to this answer, I protected the route with a decorator that would get the 'user agent' of the incoming connection and see where it comes from. If it comes from Facebook, redirect it away.
def check_for_robot(f):
#wraps(f)
def decorated(*args, **kwargs):
if 'not_a_robot' not in session:
agent = request.headers.get('User-Agent')
if request.headers.getlist("X-Forwarded-For"):
ip = request.headers.getlist("X-Forwarded-For")[0]
else:
ip = request.remote_addr
# Stop robots from crawling when sharing conversation links
# Could use the IPs too
if 'facebook' in agent or 'Slackbot' in agent:
return 'No Robots Thanks'
# Real people will get to here and continue on
session['not_a_robot'] = True
return f(*args, **kwargs)
return decorated
#app.route('/')
#check_for_robot
def index()
return 'hello human'
This issue also occurs with ANY messaging service that crawls your links to display data in the chat message (WhatsApp, Slack, etc).
This also exposed a vulnerability in these messaging services as they now return the incorrect metadata back to the chat service, but embed the link you provided, ie. Phishing, Clickjacking

Which URL made the request to my Google Apps Script?

How can I determine the source URL of a GET or POST request sent to a Google Apps Script web application?
I am making a (PayPal IPN) listener script and would like to be able to distinguish weather the request came from a the test environment (sandbox) or from the live environment.
The origin of the request to the listener determines the response from the script. The listener has to send a response back to PayPal and depending on which environment the request came from, the response needs to go back either to the sandbox server or to the live server.
I am hoping to distinguish between requests from sandbox.paypal.com or www.paypal.com, in my Google Apps Script.
To work around this requirement, I have set it manually for now:
if (PPRunMode == 'test') {//in testmode send response to sandbox site
PPUrlBase = "https://www.sandbox.paypal.com/cgi-bin/webscr";
}
else {//url for live website
PPUrlBase = "https://www.paypal.com/cgi-bin/webscr";
}
But was wondering if this can be determined automatically.
Unfortunately, no request-source information is provided to your Google Apps Script web application, so there is no direct way to determine where a request came from.
You do have the ability to provide parameters to your web app, though, so you could have the code in the sandboxed environment use that to indicate a test condition.
For example, this URL could be used by the sandboxed code for a GET request:
https://script.google.com/macros/s/---SCRIPT-ID---/exec?test=true
^^^^^^^^^^
In the doGet(e) function, you would handle the parameter like this:
function doGet(e) {
if (e.parameter.test) { //in testmode send response to sandbox site
PPUrlBase = "https://www.sandbox.paypal.com/cgi-bin/webscr";
}
else {//url for live website
PPUrlBase = "https://www.paypal.com/cgi-bin/webscr";
}
...
}
For a POST request, the solution is similar. See URL parameters in the Web Apps and Google Sites Gadgets guide for details.
If you publish your Google App Script you get two urls :
https://script.google.com/macros/s/AKfycbxsCNyssA0dzMMmsNip3DW66hiJ62ks_F1yYUn0SDu073S2dOw/exec
https://script.google.com/macros/s/AKfycbxzpvZ9e9_vzs3d6Q0ky_RHLoYDruCl-6Xm8D6YmI4/dev
You can notice the difference, not sure if that is what you are pointing to

Send gmail from web application hosted on Azure

Newbie to Azure, but got my application successfully published to the cloud as well as my needed database backends (SQL server).
Everything within the application is working as expected except email functionality. I am sending out email alerts via a gmail account, but they do not appear to get sent out. The application does not crash and trying to configure remote debugging has proven difficult.
This is the snippet I am using to send out my emails:
//Parse html document which will show in outgoing email
StreamReader reader = new StreamReader(HttpContext.Current.Server.MapPath(ConfigurationManager.AppSettings["template"]));
string body = reader.ReadToEnd();
//Populate placeholders with message variables
body = body.Replace("<%holder%>", value);
...Omitted for brevity
try
{
var smtp = new SmtpClient
{
Host = "smtp.gmail.com",
Port = 587,
EnableSsl = true,
DeliveryMethod = SmtpDeliveryMethod.Network,
UseDefaultCredentials = false,
Credentials = new NetworkCredential(fromAddress.Address, fromPassword)
};
using (var message = new MailMessage(fromAddress, toAddress)
{
IsBodyHtml = true,
Subject = subject,
Body = body,
})
{
smtp.Send(message);
}
}
Application didn't crash, so no error message to go off of. So I thought maybe it wasn't able to grab the file in the lines:
StreamReader(HttpContext.Current.Server.MapPath(ConfigurationManager.AppSettings["template"]));
string body = reader.ReadToEnd();
So I tried just sending a hardcoded string as a test:
string body = "test";
Still no email received and no error message to go off of. I'm new to azure web hosting, but is there some configuration I could be missing here? Does Azure allow sending email through third party email clients? Fyi - the above code works against localhost.
Sending e-mail from a public cloud is not as trivial as some people believe. There are a lot of things to figure out in order to not get blacklisted. Especially when you intend to use a public mail service.
My first guess is that Azure Data Center IP addresses (or the one you are hosted on) might be blacklisted by mail servers (including Microsoft's very own Office 365).
I have to also mention that recommended way for sending e-mail from an Application hosted in Azure is by using SendGrid. They have a free tier. More information from Microsoft on that subject, can be found here.
The only way to troubleshoot the exact cause of your problem is to contact GMail support and ask them if they block in any way network clients connecting from Azure cloud. Or create a VM in the same Data Center where your web application lives, install some free / trial Mail client, configure it with Google Mail and try to send e-mails. The result most probably will be same as with your application.

Google Data/OAuth/AppEngine/Python - Properly Registering a Web Application

I'm creating a webapp with this combination of tools. I'm authenticating with App Engine in the following manner:
class googleLogin(webapp.RequestHandler):
def get(self):
callbackURL = 'http://%s/googleLoginCallback' % getHost()
#Create a client service
gdClient = gdata.docs.service.DocsService()
gdata.alt.appengine.run_on_appengine(gdClient)
gdClient.SetOAuthInputParameters(gdata.auth.OAuthSignatureMethod.HMAC_SHA1,
_GoogleConsumerKey,
consumer_secret=_GoogleConsumerSecret)
#Get a Request Token
requestToken = gdClient.FetchOAuthRequestToken(scopes=_GoogleDataScope,
extra_parameters={'xoauth_displayname': APP_NAME})
#Persist token secret
self.session = Session()
self.session[TOKENSECRETKEY] = requestToken.secret
gdClient.auto_set_current_token = True
gdClient.SetOAuthToken(requestToken)
authUrl = gdClient.GenerateOAuthAuthorizationURL(callback_url=callbackURL)
self.redirect(authUrl)
I authenticated my domain with Google at https://www.google.com/accounts/ManageDomain, entering a target URL and am using the given Consumer Key/Secret. For instance, if my domain was 'juno.appspot.com', I am using http://juno.appspot.com as the target url path prefix.
The process is working; however, Google presents this message to the user in a yellow security box:
"The application that directed you
here claims to be 'xxxxxx'. We are
unable to verify this claim as the
application runs on your computer, as
opposed to a website. We recommend
that you deny access unless you trust
the application."
I don't think I should be getting this error, since my server is getting the request token and creating the authorization URL. Does anyone have any insight on how to get rid of this warning?
Google's domain registration has an option to upload a certificate, but I shouldn't need to do that because I'm using OAuth with the HMAC_SHA1 signature method.
Also, not that it should matter, but I'm doing all this through a UIWebView on the iPhone. I'm specifically trying to do all authentication server-side to avoid exposing my Consumer Key/Secret.
Thank you for any tips :)
Solved.
The culprit is this line from above:
extra_parameters={'xoauth_displayname': APP_NAME})
Setting this value for a registered application intentionally triggers a warning to users, as indicated by the Google documentation:
xoauth_displayname:
(optional) String identifying the
application. This string is displayed
to end users on Google's authorization
confirmation page. For registered
applications, the value of this
parameter overrides the name set
during registration and also triggers
a message to the user that the
identity can't be verified. For
unregistered applications, this
parameter enables them to specify an
application name, In the case of
unregistered applications, if this
parameter is not set, Google
identifies the application using the
URL value of oauth_callback; if
neither parameter is set, Google uses
the string "anonymous".
Removing this line no longer allows me to use a 'nice' name in place of the domain, but it gets rid of that annoying yellow box :)
I'm not sure exactly where the issue may be in your code, but I've got a one page oauth/appengine/gdata example which may at least set you in the right direction. Have you tried to navigate to the site directly from the iPhone/desktop browser to see what message is delivered?
Hope it helps.
Alternatively, is it possibly to do with the user agent the UIWebView sets?