How to enable HTTPS on Python 2.7 web.py? - python-2.7

I am using Python 2.7.5 with web.py (v0.38) installed on a Linux machine. Below is my code in the most basic form (webhooks.py)
#!/usr/bin/python
import web
urls = ('/.*','WebHooks')
app = web.application(urls, globals())
class WebHooks:
def POST(self):
raw_payload = web.data()
json_encode = json.loads(raw_payload)
if __name__ == '__main__':
app.run()
I execute python webhooks.py 9999
It opens up a local port http://0.0.0.0:9999/
My issue: I have read the documentation located here and I am stumped. Would somebody be able to help me open an HTTPS URL? https://0.0.0.0:9999/
What I have tried
Add the following into my code for testing:
response = app.request("/.*", https=True)
I would get an error: AttributeError: 'module' object has no attribute 'request'
I solved that issue with pip install urllib.py and then adding import urllib to the top of my code but I ended up with a bunch of errors:
Traceback (most recent call last):
File "/usr/lib/python2.7/site-packages/web/application.py", line 239, in process
return self.handle()
File "/usr/lib/python2.7/site-packages/web/application.py", line 230, in handle
return self._delegate(fn, self.fvars, args)
File "/usr/lib/python2.7/site-packages/web/application.py", line 461, in _delegate
cls = fvars[f]
KeyError: u'WebHooks'
Traceback (most recent call last):
File "/usr/lib/python2.7/site-packages/web/application.py", line 239, in process
return self.handle()
File "/usr/lib/python2.7/site-packages/web/application.py", line 229, in handle
fn, args = self._match(self.mapping, web.ctx.path)
AttributeError: 'ThreadedDict' object has no attribute 'path'

You're headed down the wrong path, but not to worry. The response = app.request("/.*", https=True) bit you're trying has to do with your application making an https request, rather then handling an https request.
See http://webpy.org/cookbook/ssl
Internally, web.py uses a CherryPyWSGIServer. To handle https, you need to provide the server with an ssl_certificate and ssl_key. Very simply, add a few lines before you invoke app.run():
if __name__ == '__main__':
from web.wsgiserver import CherryPyWSGIServer
ssl_cert = '/path-to-cert.crt'
ssl_key = '/path-to-cert.key'
CherryPyWSGIServer.ssl_certificate = ssl_cert
CherryPyWSGIServer.ssl_private_key = ssl_key
app.run()
Of course, in a full solution, you'll probably want apache or nginx to handle the https portion, but the above is perfect for small applications and testing.

Related

Is there a way could deploy Django project on namecheap in ASGI mode?

I'm trying to deploy my Django on Namecheap, the server should work but I got the following message traceback:
[ERROR] [UID:12123][2655752] wsgiAppHandler pApp->start_response() return NULL.
Traceback (most recent call last):
File "/home/alshigpf/website/passenger_wsgi.py", line 41, in __call__
return self.app(environ, start_response)
TypeError: __call__() missing 1 required positional argument: 'send'
[ERROR] [UID:12123][2655752] wsgiAppHandler pApp->start_response() return NULL.
Traceback (most recent call last):
File "/home/alshigpf/website/passenger_wsgi.py", line 41, in __call__
return self.app(environ, start_response)
TypeError: __call__() missing 1 required positional argument: 'send'
This is what my passenger_wsgi.py file looks like:
import os
import sys
import django
sys.path.append(os.getcwd())
os.environ['DJANGO_SETTINGS_MODULE'] = 'website.settings.development'
django.setup()
SCRIPT_NAME = os.getcwd()
print("Script name: ", SCRIPT_NAME)
class PassengerPathInfoFix(object):
"""
Sets PATH_INFO from REQUEST_URI because Passenger doesn't provide it.
"""
def __init__(self, app):
self.app = app
print("Start Init")
print("App is: ", self.app)
print("End Init")
def __call__(self, environ, start_response):
from urllib.parse import unquote
print("Start Calling")
environ['SCRIPT_NAME'] = SCRIPT_NAME
request_uri = unquote(environ['REQUEST_URI'])
script_name = unquote(environ.get('SCRIPT_NAME', ''))
offset = request_uri.startswith(script_name) and len(environ['SCRIPT_NAME']) or 0
environ['PATH_INFO'] = request_uri[offset:].split('?', 1)[0]
return self.app(environ, start_response)
# Get ASGI application
from website.routing import application
print("Before calling application")
application = PassengerPathInfoFix(application)
when I googled I glanced that there's something called "Uvicorn" which is an updated version of Gunicorn to handle ASGI mode.
when I did an advanced search on google to see if namecheap.com talk about using uvicorn I didn't find anything related to this problem.
so, my question is: how can I ignore this issue by still using ASGI mode instead of WSGI?

Api with flask-jwt-extended with authentication problems?

I have built an api with flask-restful and flask-jwt-extended and have correctly configured the validation passages for token expiration and invalidation. However, even though it has built the token expiration and invalid validation callbacks, api does not process correctly and reports the error: Signature has expired
On the server in the cloud, we have a Centos 7 x64 of 16gb ram, running the application using gunicorn in version 19.9.0. Using the miniconda to create the applications' python environments.
In tests in the production environment, the application complains of the expired token. However in a test environment, using Ubuntu 18.04.2, x64 with 16 gb ram, using the same settings with miniconda and gunicorn, the application has no problems executing it, returning the correct message when the token expires.
My jwt.py
from flask import Blueprint, Response, json, request
from flask_jwt_extended import (JWTManager, create_access_token,
create_refresh_token, get_jwt_identity,
jwt_required)
from app.models.core import User
from .schemas import UserSchema
from .utils import send_reponse, user_roles
def configure_jwt(app):
JWT = JWTManager(app)
#JWT.expired_token_loader
def my_expired_token_callback(expired_token):
return Response(
response=json.dumps({
"message": "Expired token"
}),
status=401,
mimetype='application/json'
)
#JWT.invalid_token_loader
def my_invalid_token_callback(invalid_token):
return Response(
response=json.dumps({
"message": "Invalid token"
}),
status=422,
mimetype='application/json'
)
Error log:
[2019-05-23 15:42:02 -0300] [3745] [ERROR] Exception on /api/company [POST]
Traceback (most recent call last):
File "/home/company/miniconda3/envs/api_ms/lib/python3.6/site-packages/flask/app.py", line 1813, in full_dispatch_request
rv = self.dispatch_request()
File "/home/company/miniconda3/envs/api_ms/lib/python3.6/site-packages/flask/app.py", line 1799, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/home/company/miniconda3/envs/api_ms/lib/python3.6/site-packages/flask_restful/__init__.py", line 458, in wrapper
resp = resource(*args, **kwargs)
File "/home/company/miniconda3/envs/api_ms/lib/python3.6/site-packages/flask/views.py", line 88, in view
return self.dispatch_request(*args, **kwargs)
File "/home/company/miniconda3/envs/api_ms/lib/python3.6/site-packages/flask_restful/__init__.py", line 573, in dispatch_request
resp = meth(*args, **kwargs)
File "/home/company/miniconda3/envs/api_ms/lib/python3.6/site-packages/flask_jwt_extended/view_decorators.py", line 102, in wrapper
verify_jwt_in_request()
File "/home/company/miniconda3/envs/api_ms/lib/python3.6/site-packages/flask_jwt_extended/view_decorators.py", line 31, in verify_jwt_in_request
jwt_data = _decode_jwt_from_request(request_type='access')
File "/home/company/miniconda3/envs/api_ms/lib/python3.6/site-packages/flask_jwt_extended/view_decorators.py", line 266, in _decode_jwt_from_request
decoded_token = decode_token(encoded_token, csrf_token)
File "/home/company/miniconda3/envs/api_ms/lib/python3.6/site-packages/flask_jwt_extended/utils.py", line 107, in decode_token
allow_expired=allow_expired
File "/home/company/miniconda3/envs/api_ms/lib/python3.6/site-packages/flask_jwt_extended/tokens.py", line 138, in decode_jwt
leeway=leeway, options=options)
File "/home/company/miniconda3/envs/api_ms/lib/python3.6/site-packages/jwt/api_jwt.py", line 104, in decode
self._validate_claims(payload, merged_options, **kwargs)
File "/home/company/miniconda3/envs/api_ms/lib/python3.6/site-packages/jwt/api_jwt.py", line 134, in _validate_claims
self._validate_exp(payload, now, leeway)
File "/home/company/miniconda3/envs/api_ms/lib/python3.6/site-packages/jwt/api_jwt.py", line 175, in _validate_exp
raise ExpiredSignatureError('Signature has expired')
jwt.exceptions.ExpiredSignatureError: Signature has expired
I'm trying to understand why the application is able to correctly return the token expiration message in the test environment, where in the production environment it returns the error code 500 Internal Server Error. In addition to fixing this problem in our application.
Based on this link found inside the project repository, I discovered that the problem is related to the flask configuration option called PROPAGATE_EXCEPTIONS, which must be True.
The issue in the flask-jwt-extended repository that helped me find the answer.
This comment states that Flask Restful needs to ignore JWT and JWT Extended Exceptions and provides a simple snippet that solves the issue.
Copying the code from above link,
from flask_jwt_extended.exceptions import JWTExtendedException
from jwt.exceptions import PyJWTError
class FixedApi(Api):
def error_router(self, original_handler, e):
if not isinstance(e, PyJWTError) and not isinstance(e, JWTExtendedException) and self._has_fr_route():
try:
return self.handle_error(e)
except Exception:
pass # Fall through to original handler
return original_handler(e)

Flask Security - Send confirmation email?

I am trying to create a flask boilerplate app and I am running into an error when I try to run a flask-script. I am getting an error that I don't fully understand, the code is broken up into several modules so it may be best to post the link to the repository. The two parts in the traceback that are my code are an import from the app and the creation of the security object.
The two files that are causing conflict are:
manage.py
app/__init__.py
What caused the problem is that I set several security variables to true:
SECURITY_REGISTERABLE = True
SECURITY_SEND_REGISTER_EMAIL = True
SECURITY_CONFIRMABLE = True
SECURITY_CONFIRM_URL = True
SECURITY_EMAIL_SENDER = 'some_email_account'
SECURITY_CONFIRM_LOGIN_WITHOUT_CONFIRMATION = False
SECURITY_TRACKABLE = True
SECURITY_CHANGEABLE = True
The project can be found here:
github link
Traceback (most recent call last):
File "manage.py", line 4, in <module>
from app import app, db, Role, user_datastore
File "C:\Users\...\dev\flask-boilerplate\app\__init__.py", line 22, in <module>
security = Security(app, user_datastore)
File "C:\Users\...\dev\flask-boilerplate\venv\lib\site-packages\flask_security\core.py", line 469, in __init__
self._state = self.init_app(app, datastore, **kwargs)
File "C:\Users\...\dev\flask-boilerplate\venv\lib\site-packages\flask_security\core.py", line 507, in init_app
app.register_blueprint(create_blueprint(state, __name__))
File "C:\Users\...\dev\flask-boilerplate\venv\lib\site-packages\flask_security\views.py", line 383, in create_blueprint
'<token>'),
File "C:\Users\...\dev\flask-boilerplate\venv\lib\site-packages\flask_security\utils.py", line 249, in slash_url_suffix
return url.endswith('/') and ('%s/' % suffix) or ('/%s' % suffix)
AttributeError: 'bool' object has no attribute 'endswith'
SECURITY_CONFIRM_URL must be a string (i.e. SECURITY_CONFIRM_URL='https://google.com)

Log warning from Selenium on Django [duplicate]

Whenever I try to construct a string based on self.live_server_url, I get python TypeError messages. For example, I've tried the following string constructions (form 1 & 2 below), but I experience the same TypeError. My desired string is the Live Server URL with "/lists" appended. NOTE: the actual test does succeed to create a server and I can manually access the server, and more specifically, I can manually access the exact URL that I'm trying to build programmatically (e.g. 'http://localhost:8081/lists').
TypeErrors occur with these string constructions.
# FORM 1
lists_live_server_url = '%s%s' % (self.live_server_url, '/lists')
# FORM 2
lists_live_server_url = '{0}{1}'.format(self.live_server_url, '/lists')
self.browser.get(lists_live_server_url)
There is no python error with this form (nothing appended to string), albeit my test fails (as I would expect since it isn't accessing /lists).
self.browser.get(self.live_server_url)
Here is the python error that I'm getting.
/usr/local/Cellar/python3/3.4.2_1/Frameworks/Python.framework/Versions/3.4/bin/python3.4 /Applications/PyCharm.app/Contents/helpers/pycharm/django_test_manage.py test functional_tests.lists_tests.LiveNewVisitorTest.test_can_start_a_list_and_retrieve_it_later /Users/myusername/PycharmProjects/mysite_proj
Testing started at 11:55 AM ...
Creating test database for alias 'default'...
Traceback (most recent call last):
File "/usr/local/Cellar/python3/3.4.2_1/Frameworks/Python.framework/Versions/3.4/lib/python3.4/wsgiref/handlers.py", line 137, in run
self.result = application(self.environ, self.start_response)
File "/usr/local/lib/python3.4/site-packages/django/test/testcases.py", line 1104, in __call__
return super(FSFilesHandler, self).__call__(environ, start_response)
File "/usr/local/lib/python3.4/site-packages/django/core/handlers/wsgi.py", line 189, in __call__
response = self.get_response(request)
File "/usr/local/lib/python3.4/site-packages/django/test/testcases.py", line 1087, in get_response
return self.serve(request)
File "/usr/local/lib/python3.4/site-packages/django/test/testcases.py", line 1099, in serve
return serve(request, final_rel_path, document_root=self.get_base_dir())
File "/usr/local/lib/python3.4/site-packages/django/views/static.py", line 54, in serve
fullpath = os.path.join(document_root, newpath)
File "/usr/local/Cellar/python3/3.4.2_1/Frameworks/Python.framework/Versions/3.4/lib/python3.4/posixpath.py", line 82, in join
path += b
TypeError: unsupported operand type(s) for +=: 'NoneType' and 'str'
Am I unknowingly attempting to modify the live_server_url, which is leading to these TypeErrors? How could I programmatically build a string of live_server_url + "/lists"?
Here is the test that I am attempting...
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from django.test import LiveServerTestCase
class LiveNewVisitorTest(LiveServerTestCase):
def setUp(self):
self.browser = webdriver.Chrome()
self.browser.implicitly_wait(3)
def tearDown(self):
self.browser.close()
def test_can_start_a_list_and_retrieve_it_later(self):
#self.browser.get('http://localhost:8000/lists')
#self.browser.get('http://www.google.com')
#lists_live_server_url = '%s%s' % (self.live_server_url, '/lists')
#lists_live_server_url = '{0}{1}'.format(self.live_server_url, '/lists')
lists_live_server_url = self.live_server_url
self.browser.get(lists_live_server_url)
self.assertIn('To-Do', self.browser.title)
header_text = self.browser.find_element_by_tag_name('h1').text
self.assertIn('To-Do', header_text)
See this discussion on Reddit featuring the same error Traceback.
Basically, this is not a problem with anything within the Selenium tests but rather with your project's static file configuration.
From your question, I believe the key line within the Traceback is:
File "/usr/local/lib/python3.4/site-packages/django/views/static.py", line 54, in serve
fullpath = os.path.join(document_root, newpath)
This line indicates that an unsuccessful os.path.join is being attempted within django.views.static.
Set STATIC_ROOT in your project's settings.pyfile and you should be good.
Use StaticLiveServerTestCase instead may help

Selenium get stuck while connecting to Firefox

I'm working on a website with Python 3 and Django 1.6. I wanted to create a view, which renders a particular element from my site to a png. Therefore I use Selenium to remote control Firefox to get a specific page from my webserver and the fetching a screenshot for the response. The following code is written for this purpose:
def do_get(self, *args, **kwargs):
from pyvirtualdisplay import Display
from selenium import webdriver
import base64
display = Display(visible=0, size=(200, 100))
display.start()
browser = webdriver.Firefox()
browser.get('http://www.google.com')
response = base64.b64decode(browser.get_screenshot_as_base64())
browser.quit()
display.stop()
return HttpResponse(content=response, mimetype='image/png')
The problem is, that if I'm running the code via the python3 console directly as root everything is working fine. But my apache works with a different user without root permissions. When I try to execute the code with this user, the code is stuck in the line
browser = webdriver.Firefox()
It seems that Selenium can't connect to Firefox, when I interrupt the exection following traceback occurs:
Traceback (most recent call last):
File "test.py", line 6, in <module>
browser = webdriver.Firefox()
File "/usr/local/lib/python3.4/dist-packages/selenium/webdriver/firefox/webdriver.py", line 59, in __init__
self.binary, timeout),
File "/usr/local/lib/python3.4/dist-packages/selenium/webdriver/firefox/extension_connection.py", line 47, in __init__
self.binary.launch_browser(self.profile)
File "/usr/local/lib/python3.4/dist-packages/selenium/webdriver/firefox/firefox_binary.py", line 60, in launch_browser
self._start_from_profile_path(self.profile.path)
File "/usr/local/lib/python3.4/dist-packages/selenium/webdriver/firefox/firefox_binary.py", line 83, in _start_from_profile_path
env=self._firefox_env).communicate()
File "/usr/lib/python3.4/subprocess.py", line 936, in communicate
stdout = _eintr_retry_call(self.stdout.read)
File "/usr/lib/python3.4/subprocess.py", line 487, in _eintr_retry_call
return func(*args)
It seems to be a user permission issue, therefore I changed the owner of the installed firefox to my apache user. I can run firefox from the console with this user, but with the webserver the problem persists. My server is running a Ubuntu 14.04 LTS instance.
Any ideas?
Are you on the latest version of Firefox? I upgraded to version 32 this morning and the webdriver plugin is no longer supported.
Mozilla support suggests using Chrome instead of downgrading :-(