Python3 Slack RTMClient in not working behind proxy - python-3.x

I am trying to create a simple Python bot for my project. Everything is working fine on my localhost, but the same code stops working behind the network firewall which needs environment proxy to be set.
from slack import RTMClient
proxy='http://XXXX:NNNN'
token='XXXX'
class Botso():
def __init__(self):
self.proxy=self.get_proxy()
self.rt= RTMClient(
token=token,
connect_method='rtm.start',
proxy=self.proxy
)
def get_proxy(self):
host=socket.gethostname()
if "internal" in host:
return None
elif "XXX" in host:
return proxy
#RTMClient.run_on(event="message")
def say_hello(**payload):
data = payload['data']
web_client = payload['web_client']
if 'text' in data and 'hii' in data['text']:
channel_id = data['channel']
thread_ts = data['ts']
user = data['user'] # This is not username but user ID (the format is either U*** or W***)
web_client.chat_postMessage(
channel=channel_id,
text=f"Hi <#{user}>!"
#thread_ts=thread_ts
)
if __name__ == '__main__':
botso=Botso()
botso.rt.start()
The error I am getting while initializing the RTMClient is
Traceback (most recent call last):
File "botso.py" , in <module>
botso.rt.start()
File "/usr/lib64/python3.6/http/client.py", line 974, in send
self.connect()
File "/usr/lib64/python3.6/http/client.py", line 1407, in connect
super().connect()
File "/usr/lib64/python3.6/http/client.py", line 950, in connect
self._tunnel()
File "/usr/lib64/python3.6/http/client.py", line 929, in _tunnel
message.strip()))
OSError: Tunnel connection failed: 403 Forbidden
I have other code in the same environment which uses the same proxy to send slack messages and works fine bu using request api.
params={
'token': self.slack_token,
'types': ['public_channel','private_channel']
}
slack_url='https://slack.com/api/conversations.list'
response = requests.get(url=slack_url,params=params,proxies=self.proxy).json()
How can we make the RTMClient work with proxy and Python3.
Couldn't find much help in slack API documents.

Related

Why can't upload file into the dropbox with proxy?

The urllib library installed in my os:
pip list |grep urllib
urllib3 1.25.11
I want to upload local file into the dropbox with proxy:
import dropbox
access_token = "xxxxxx"
file_from = "local_file"
file_to = "/directory_in_dropbox"
proxyDict = {
"http": "http://127.0.0.1:8123",
"https": "https://127.0.0.1:8123"
}
mysesh = dropbox.create_session(1,proxyDict)
dbx = dropbox.Dropbox(access_token,session=mysesh)
with open(file_from, 'rb') as f:
dbx.files_upload(f.read(), file_to)
It encounter errors:
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "/home/debian/.local/lib/python3.9/site-packages/dropbox/base.py", line 3208, in files_upload
r = self.request(
File "/home/debian/.local/lib/python3.9/site-packages/dropbox/dropbox_client.py", line 326, in request
res = self.request_json_string_with_retry(host,
File "/home/debian/.local/lib/python3.9/site-packages/dropbox/dropbox_client.py", line 476, in request_json_string_with_retry
return self.request_json_string(host,
File "/home/debian/.local/lib/python3.9/site-packages/dropbox/dropbox_client.py", line 589, in request_json_string
r = self._session.post(url,
File "/usr/lib/python3/dist-packages/requests/sessions.py", line 590, in post
return self.request('POST', url, data=data, json=json, **kwargs)
File "/usr/lib/python3/dist-packages/requests/sessions.py", line 542, in request
resp = self.send(prep, **send_kwargs)
File "/usr/lib/python3/dist-packages/requests/sessions.py", line 655, in send
r = adapter.send(request, **kwargs)
File "/usr/lib/python3/dist-packages/requests/adapters.py", line 439, in send
resp = conn.urlopen(
File "/usr/lib/python3/dist-packages/urllib3/connectionpool.py", line 696, in urlopen
self._prepare_proxy(conn)
File "/usr/lib/python3/dist-packages/urllib3/connectionpool.py", line 966, in _prepare_proxy
conn.connect()
File "/usr/lib/python3/dist-packages/urllib3/connection.py", line 359, in connect
conn = self._connect_tls_proxy(hostname, conn)
File "/usr/lib/python3/dist-packages/urllib3/connection.py", line 500, in _connect_tls_proxy
return ssl_wrap_socket(
File "/usr/lib/python3/dist-packages/urllib3/util/ssl_.py", line 453, in ssl_wrap_socket
ssl_sock = _ssl_wrap_socket_impl(sock, context, tls_in_tls)
File "/usr/lib/python3/dist-packages/urllib3/util/ssl_.py", line 495, in _ssl_wrap_socket_impl
return ssl_context.wrap_socket(sock)
File "/usr/lib/python3.9/ssl.py", line 500, in wrap_socket
return self.sslsocket_class._create(
File "/usr/lib/python3.9/ssl.py", line 997, in _create
raise ValueError("check_hostname requires server_hostname")
ValueError: check_hostname requires server_hostname
It's no use to write the proxy dict as below:
proxyDict = {
"http": "http://127.0.0.1:8123",
"https": "http://127.0.0.1:8123"
}
The proxy 127.0.0.1:8123 works fine,i can down resources from web with proxy in youtube-dl command:
youtube-dl --proxy http://127.0.0.1:8118 $url
Updated for Paulo's advice:
Updaed for Markus' advice:
import ssl
ssl._create_default_https_context = ssl._create_unverified_context
ssl.SSLContext.verify_mode = property(lambda self: ssl.CERT_NONE, lambda self, newval: None)
import dropbox
access_token = "xxxxxxxx"
file_from = "/home/debian/sample.sql"
file_to = "/mydoc"
proxyDict = {
"http": "http://127.0.0.1:8123",
"https": "https://127.0.0.1:8123"
}
mysesh = dropbox.create_session(1,proxyDict)
dbx = dropbox.Dropbox(access_token,session=mysesh)
with open(file_from, 'rb') as f:
dbx.files_upload(f.read(), file_to)
It encounter the below error:
/home/debian/.local/lib/python3.9/site-packages/urllib3/connectionpool.py:981: InsecureRequestWarning: Unverified HTTPS request is being made to host '127.0.0.1'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings
warnings.warn(
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "/home/debian/.local/lib/python3.9/site-packages/dropbox/base.py", line 3208, in files_upload
r = self.request(
File "/home/debian/.local/lib/python3.9/site-packages/dropbox/dropbox_client.py", line 326, in request
res = self.request_json_string_with_retry(host,
File "/home/debian/.local/lib/python3.9/site-packages/dropbox/dropbox_client.py", line 476, in request_json_string_with_retry
return self.request_json_string(host,
File "/home/debian/.local/lib/python3.9/site-packages/dropbox/dropbox_client.py", line 596, in request_json_string
self.raise_dropbox_error_for_resp(r)
File "/home/debian/.local/lib/python3.9/site-packages/dropbox/dropbox_client.py", line 639, in raise_dropbox_error_for_resp
raise AuthError(request_id, err)
dropbox.exceptions.AuthError: AuthError('xxxxxxxxxxxxxxxxxxxxxx', AuthError('invalid_access_token', None))
Update for Life is complex's advice:
I tried many times to get mysesh = dropbox.create_session(1,proxyDict) to work correctly.
I decided to look at the code for dropbox-sdk-python and noted that it is calling requests.Session(). So I decided to use that over dropbox.create_session()
import requests
from dropbox import Dropbox
from dropbox.files import WriteMode
access_token = "my_access_token"
file_from = 'test.docx'
file_to = '/test.docx'
# https://free-proxy-list.net
proxyDict = {
"http": "http://50.218.57.65:80",
"https": "https://83.229.73.175:80"
}
s = requests.Session()
s.proxies = proxyDict
dbx = Dropbox(access_token, session=s)
with open(file_from, 'rb') as f:
file_content = f.read()
dbx.files_upload(f=file_content, path=file_to, mode=WriteMode.overwrite, mute=False)
Here is a screenshot of the file being written to DropBox.
I have tried this code with multiple proxy servers and it works each time.
Tldr;
So far, my understanding is it may be
Miss-use of the urllib
Bad https certificates
Solution (maybe)
urllib format
If I remember well urllib changed his format at some point from
proxyDict = {
'http':'8.88.888.8:8888',
'https':'8.88.888.8:8888'
}
proxyDict = {
'https': 'https://8.88.888.8:8888',
'http': 'http://8.88.888.8:8888',
}
Have you tried both format ?
You must have a problem with
your proxy not forwarding some stuff the right way or
your access token is wrong
the Dropbox app has the wrong permissions set
because this code (which is basically what you have in your question - even without disabling SSL certificate check!) works just fine with my access token put into the environment variable DROPBOX_ACCESS_TOKEN.
import dropbox
import sys
import os
DROPBOX_ACCESS_TOKEN = os.getenv('DROPBOX_ACCESS_TOKEN')
def uploadFile(fromFilePath,toFilePath):
proxy = '127.0.0.1:3128' # locally installed squid proxy server
proxyDict = {
"http": "http://"+proxy,
"https": "http://"+proxy # connection to proxy is http!!
}
session = dropbox.create_session(1,proxyDict)
client = dropbox.Dropbox(DROPBOX_ACCESS_TOKEN,session)
client.files_upload(open(fromFilePath, "rb").read(), toFilePath)
print("Done uploading {} to {}".format(fromFilePath,toFilePath))
if __name__=="__main__":
uploadFile(sys.argv[1],sys.argv[2])
Be aware though, that the access token - once it is generated - has the permissions that were in effect at the time of token generation. If you change the app's permissions AFTER generating the token, the token will still have the original permissions!
EDIT: It looks like, the Dropbox API is clever enough to NOT use the proxy, if it can reach the target directly. Thus this code is working with ANYTHING you put into the proxyDict and it is not at all clear, if the code works, if it really has to go through the proxy. I am working on verifying that and will update the answer accordingly.
Update: I installed squid on my MacBook and used http://127.0.0.1:3128 as the proxy in above code, but the logs showed, the code never even tried to go through the proxy. But once I set the environment variables http_proxy and https_proxy to "http://127.0.0.1:3128" the request WOULD go through the proxy and proceed successfully. So... either there is something going on, I don't fully understand or the Dropbox API has some problem with the proxy definitions in the create_session call. Time to look at the API source code I guess...
Thank for Life is complex's code,i add permission on Files and folders.
And re-generate the dropbox token ,execute the same code (nothing changed) with the new token ,done!
It is nothing related with proxy setting,just dropbox setting!

flask mail error “SMTPServerDisconnected('please run connect() first')”

I am writing a little web application based on Miguel Grinberg's Flasky. I use the exact same code for user send reset password mail using gmail.
The following as my email.py file here i can implement mail sending function
def send_password_reset_email(user):
token = user.get_reset_password_token()
send_email(_('[Microblog] Reset Your Password'),
sender=current_app.config['ADMINS'][0],
recipients=[user.email],
text_body=render_template('email/reset_password.txt',
user=user, token=token),
html_body=render_template('email/reset_password.html',
user=user, token=token))
def send_async_email(app, msg):
with app.app_context():
mail.send(msg)
def send_email(subject, sender, recipients, text_body, html_body):
msg = Message(subject, sender=sender, recipients=recipients)
msg.body = text_body
msg.html = html_body
Thread(target=send_async_email,
args=(current_app._get_current_object(), msg)).start()
In routes.py file im getting email from the user and if the user email match then i well send the token to the user via mail
#bp.route('/reset_password_request', methods=['GET', 'POST'])
def reset_password_request():
if current_user.is_authenticated:
return redirect(url_for('main.index'))
form = ResetPasswordRequestForm()
if form.validate_on_submit():
user = User.query.filter_by(email=form.email.data).first()
if user:
send_password_reset_email(user)
flash(
_('Check your email for the instructions to reset your password'))
return redirect(url_for('auth.login'))
return render_template('auth/reset_password_request.html',
title=_('Reset Password'), form=form)
#bp.route('/reset_password/<token>', methods=['GET', 'POST'])
def reset_password(token):
if current_user.is_authenticated:
return redirect(url_for('main.index'))
user = User.verify_reset_password_token(token)
if not user:
return redirect(url_for('main.index'))
form = ResetPasswordForm()
if form.validate_on_submit():
user.set_password(form.password.data)
db.session.commit()
flash(_('Your password has been reset.'))
return redirect(url_for('auth.login'))
return render_template('auth/reset_password.html', form=form)
In model.py file in the user model i generate a token for a user and also check the user token
def get_reset_password_token(self, expires_in=600):
return jwt.encode(
{'reset_password': self.id, 'exp': time() + expires_in},
current_app.config['SECRET_KEY'],
algorithm='HS256').decode('utf-8')
#staticmethod
def varify_reset_password_token(token):
try:
id = jwt.decode(token, current_app.config['SECRET_KEY'],
algorithms=['HS256'])['reset_password']
except:
return
return User.query.get(id)
my flask mail setup is as follows config.py file
MAIL_SERVER = os.environ.get('MAIL_SERVER')
MAIL_PORT = int(os.environ.get('MAIL_PORT') or 25)
MAIL_USE_TLS = os.environ.get('MAIL_USE_TLS') is not None
MAIL_USERNAME = os.environ.get('MAIL_USERNAME')
MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD')
ADMINS =['socialtraffic#gmail.com']
The following Error i get in the terminal
Traceback (most recent call last):
File "c:\python38\lib\threading.py", line 932, in _bootstrap_inner
self.run()
File "c:\python38\lib\threading.py", line 870, in run
self._target(*self._args, **self._kwargs)
File "C:\Users\Ijaz Bacha\project\microblog1\app\email.py", line 9, in send_async_email
mail.send(msg)
File "c:\users\ijaz bacha\project\microblog1\venv\lib\site-packages\flask_mail.py", line 492, in send
message.send(connection)
File "c:\users\ijaz bacha\project\microblog1\venv\lib\site-packages\flask_mail.py", line 152, in __exit__
self.host.quit()
File "c:\python38\lib\smtplib.py", line 988, in quit
res = self.docmd("quit")
File "c:\python38\lib\smtplib.py", line 424, in docmd
self.putcmd(cmd, args)
File "c:\python38\lib\smtplib.py", line 371, in putcmd
self.send(str)
File "c:\python38\lib\smtplib.py", line 363, in send
raise SMTPServerDisconnected('please run connect() first')
smtplib.SMTPServerDisconnected: please run connect() first
I am also doing the same tutorial and ran into the same problem. I found the answer on Miguel's Blog:
You need two terminal windows.
The first terminal running your local mail server that emulates your emails being sent:
$(venv) python -m smtpd -n -c DebuggingServer localhost:8025
Your main flask terminal window with the following required commands (FLASK_DEBUG=1 is optional but highly recommended for troubleshooting):
$ export FLASK_APP=microblog.py
$ export FLASK_DEBUG=1
$ export MAIL_SERVER=localhost
$ export MAIL_PORT=8025
$ flask run
This solved my problems.
In my experience, a while ago I had a very similar issue that you you were having. After troubleshooting, I found out that my code worked when I would create a mail class, and call function like $mailclass.ehlo etc.
Based on the error its having an issue connecting or staying connected. Try calling the connect methods in the function itself and close of the connection after each email.
I decided to change the following line in the app/__init__.py file:
mail = Mail(app)
with:
mail = Mail()
mail.init_app(app)
Solved the issue for me

Python Flask - get the userList from http://localhost:8080/users

I am new to Flask and wanted to develop a micro-service application that can get the data from other microservice (written in spring boots) running in http://localhost:8080/users.
The data looks like this:
{"userList":[{"userId":1,"name":"x","email":"x#gmail.com","address":"add1","phone":"123","accountNo":"0000001"},{"userId":2,"name":"y","email":"x#gmail.com","address":"add1","phone":"123","accountNo":"0000001"}
My code is like below:
from flask import Flask, jsonify, request
import logging
app = Flask(__name__)
os.environ['NO_PROXY'] = '127.0.0.1'
r = request.get('http://127.0.0.1:8080')
#app.route('/users', methods=['GET'])
def cust_search(email):
json = request.get_json()
if __name__ == '__main__':
app.logger.setLevel(logging.INFO)
app.run(debug=True)
I get the below error message when I run in venv:
File "", line 13, in <module>
r = request.get('http://127.0.0.1:8080')
File "", line 347, in __getattr__
return getattr(self._get_current_object(), name)
File "/covid_service/venv/lib/python3.7/site-packages/werkzeug/local.py", line 306, in _get_current_object
return self.__local()
File "/covid_service/venv/lib/python3.7/site-packages/flask/globals.py", line 38, in _lookup_req_object
raise RuntimeError(_request_ctx_err_msg)
RuntimeError: Working outside of request context.
This typically means that you attempted to use functionality that needed
an active HTTP request. Consult the documentation on testing for
information about how to avoid this problem.
Any help please
For what you are doing, you need to use the builtin requests module.
import requests
users = requests.get('http://127.0.0.1:8080').json()
flask.request is different than requests. It used for handling request data passed to the server, typically from a form post, and as you stated requires an active HTTP request.

Issue when trying to send emails through Python

OS: MacCatalinva V10.15.3
Python: 3.7.7
PiP: 20.0.2
Hey,
I'm new to coding so I'm not sure what this really means.
I'm trying to send emails via Python through Gmail, I've set my account to accept "Less secure app access" and followed the steps in this guide, but all I get is the following:
`[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1076)
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/smtplib.py", line 354, in send
self.sock.sendall(s)
OSError: [Errno 9] Bad file descriptor
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/Users/mymac/Desktop/Test2.py", line 34, in
server.quit()
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/smtplib.py", line 984, in quit
res = self.docmd("quit")
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/smtplib.py", line 420, in docmd
self.putcmd(cmd, args)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/smtplib.py", line 367, in putcmd
self.send(str)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/smtplib.py", line 357, in send
raise SMTPServerDisconnected('Server not connected')
smtplib.SMTPServerDisconnected: Server not connected`
And this is my Code:
import smtplib
import ssl
sender_email = "myemailadress#gmail.com"
receiver_email = "myadress#hotmail.com"
message = """\
Subject: Hi there
This message is sent from Python."""
# Send email here
smtp_server = "smtp.gmail.com"
port = 587 # For starttls
sender_email = "myemailadress#gmail.com"
password = input("Type your password and press enter: ")
# Create a secure SSL context
context = ssl.create_default_context()
# Try to log in to server and send email
try:
server = smtplib.SMTP(smtp_server, port)
server.ehlo() # Can be omitted
server.starttls(context=context) # Secure the connection
server.ehlo() # Can be omitted
server.login(sender_email, password)
# TODO: Send email here
except Exception as e:
# Print any error messages to stdout
print(e)
finally:
server.quit()
1)After this line:
server.login(sender_email, password)
make sure to send the message you have it.
For that:
server.sendmail(sender_email,receiver_email,message)
that's it, I hope.

Sending my first message on the slack API

I registered my first app, and it looks like this:
All of the fields are populated below the screen shot.
Now, I have some basic python code using the examples found on their repo.
I create the following test script:
import traceback
app_id = 'FAKE.VALUE'
client_id = 'FAKE.VALUE'
client_secret = 'FAKE.VALUE'
signin_secret = 'FAKE.VALUE'
verification_token = 'FAKE.VALUE'
items = locals()
import os
import slack
items = locals().copy()
for k in items:
if '__' not in k:
val = items[k]
try:
client = slack.WebClient(token=val)
response = client.chat_postMessage(
channel='CE476K9HT',
text='Hello-----' + str(val))
print(response)
except:
print(k)
traceback.print_exc()
print('-'*50)
But all of the responses I get say:
The server responses with: {'ok':False,'error':'invalid_auth'}
For some reason, is it necessary to use path variables?
It is unclear to me what type of auth is required here.
After doing what Erik suggested,
I have a xoxp code and registered the redirect url to http://localhost.
and added the following scopes:
and updated my code to look like:
oauth_token ='xoxp-*****************'
import os
import slack
items = locals().copy()
client = slack.WebClient(token=oauth_token)
response = client.chat_postMessage(
channel='my_channel_id',
text='Hello-----')
I got my channel ID from the url:
https://app.slack.com/client/FOO/my_channel_id
When I run my code, I get the following back:
Traceback (most recent call last):
File "/home/usr/git/slack_messaging/slack_messaging.py", line 20, in <module>
text='Hello-----')
File "/home/usr/git/python-slackclient/slack/web/client.py", line 382, in chat_postMessage
return self.api_call("chat.postMessage", json=kwargs)
File "/home/usr/git/python-slackclient/slack/web/base_client.py", line 172, in api_call
return self._event_loop.run_until_complete(future)
File "/home/usr/anaconda2/envs/beer/lib/python3.7/asyncio/base_events.py", line 573, in run_until_complete
return future.result()
File "/home/usr/git/python-slackclient/slack/web/base_client.py", line 241, in _send
return SlackResponse(**{**data, **res}).validate()
File "/home/usr/git/python-slackclient/slack/web/slack_response.py", line 176, in validate
raise e.SlackApiError(message=msg, response=self)
slack.errors.SlackApiError: The request to the Slack API failed.
The server responded with: {'ok': False, 'error': 'missing_scope', 'needed': 'chat:write:user', 'provided': 'admin,identify'}
Process finished with exit code 1
You need two things to make your script work.
1. OAuth token
You need a valid OAuth token and provide it when initializing the Slack Client:
client = slack.WebClient(token="xoxb-xxx")
To get a token you need to install your Slack app to a workspace. You can do that on the app management page under "Install App". Your OAuth token will also be displayed on that page once you installed it.
2. Permissions
Your Oauth Token / Slack app needs to have the permission to post messages. On the app management pages go to "OAuth & permission" and add the needed permission to your app:. e.g. chat:write:user for user tokens.
Note that you need to reinstall your app every time to add a permission.

Resources