Calling flask via javascript run on an https external site - javascript

There is an external site that runs https. I have a UI based "server" that I can run javascript from.
I want to have that site send me a XMLHttpRequest() via my javascript running on their site to my Flask_Restful running elsewhere.
This code works, but only on http sites. Their site is https.
I am currently running this code on the chrome console when on their site.
var xhttp = new XMLHttpRequest();
xhttp.open("PUT", "http://[my_server]:5000/todos/todo3", true);`
xhttp.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhttp.send(JSON.stringify({ "task": "new task2"}));
So I get the error:
This request has been blocked; the content must be served over HTTPS.
If I run it with https I get the error:
OPTIONS https://9[my_flask_server]:5000/todos/todo3 net::ERR_SSL_PROTOCOL_ERROR
My Flask server also prints out:
code 400, message Bad request syntax ('\x16...
How do I enable my flask site to allow this SSL call?
I have enabled CORS like this:
from flask import Flask
from flask_restful import reqparse, abort, Api, Resource
from flask_cors import CORS, cross_origin
app = Flask(__name__)
CORS(app)
api = Api(app)
EDIT 1
I am trying to add ssl capabilities to my server.
I have made a host.cert file and a host.key file by using this:
openssl genrsa 1024 > host.key
chmod 400 host.key
openssl req -new -x509 -nodes -sha1 -days 365 -key host.key -out host.cert
source: https://serverfault.com/questions/224122/what-is-crt-and-key-and-how-can-i-generate-them
And I updated my Flask app.py such that the top looks like this:
from flask import Flask
from flask_restful import reqparse, abort, Api, Resource
from flask_cors import CORS, cross_origin
from OpenSSL import SSL
context = SSL.Context(SSL.SSLv23_METHOD)
context.use_privatekey_file('host.key')
context.use_certificate_file('host.cert')
app = Flask(__name__)
CORS(app)
api = Api(app)
source: http://flask.pocoo.org/snippets/111/
When I run python app.py it errors out now.
Current error:
Traceback (most recent call last):
File "app.py", line 72, in <module>
app.run(host="[my_server]", port="5000", ssl_context=context)
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 841, in run
run_simple(host, port, self, **options)
File "/usr/local/lib/python2.7/dist-packages/werkzeug/serving.py", line 742, in run_simple
inner()
File "/usr/local/lib/python2.7/dist-packages/werkzeug/serving.py", line 702, in inner
fd=fd)
File "/usr/local/lib/python2.7/dist-packages/werkzeug/serving.py", line 596, in make_server
passthrough_errors, ssl_context, fd=fd)
File "/usr/local/lib/python2.7/dist-packages/werkzeug/serving.py", line 528, in __init__
self.socket = ssl_context.wrap_socket(sock, server_side=True)
AttributeError: 'OpenSSL.SSL.Context' object has no attribute 'wrap_socket'
EDIT 2: (didn't work)
sudo pip install 'Werkzeug==0.9.6'
Changes the issue to:
Traceback (most recent call last):
File "/usr/lib/python2.7/logging/__init__.py", line 851, in emit
msg = self.format(record)
File "/usr/lib/python2.7/logging/__init__.py", line 724, in format
return fmt.format(record)
File "/usr/lib/python2.7/logging/__init__.py", line 464, in format
record.message = record.getMessage()
File "/usr/lib/python2.7/logging/__init__.py", line 328, in getMessage
msg = msg % self.args
TypeError: %d format: a number is required, not str
Logged from file _internal.py, line 87
EDIT 3: PROGRESS
Using just
from OpenSSL import SSL
...
and
...
if __name__ == '__main__':
context = ('host.crt', 'host.key')
app.run(host...
Has changed the console side error from:
OPTIONS https://[my_flask_server]:5000/todos/todo3 net::ERR_SSL_PROTOCOL_ERROR
to
OPTIONS https://[my_flask_server]:5000/todos/todo3 net::ERR_INSECURE_RESPONSE
EDIT 3
At this point its just browser related security checks since my ssl certificate is not recognized / weak. I think I've got it working as well as I can, Im gonna try and get it more authorized i guess?

Related

unable to use getCurrentPosition() in a Flask local host app

I'm working on a python flask app for practice. I want to access the getCurrentPosition() of JS to get the geolocation. However, as the app is running on http://localhost:5000/ I'm getting an error that getCurrentPosition() and watchPosition() are deprecated on insecure origins.
Is there a way that it will work on the flask localhost server?
I have found the resolution. Geolocation can only be used in HTTPS requests.
In order to convert your localhost flask app to HTTPS from HTTP, you have to use OpenSSL to create a key and certificate.
Follow the below step to set up your HTTPS environment for the flask localhost server
If you have installed Git then OpenSSL command comes in a package. Open git bash where you want to store the files.
Run the below command in Git Bash.
openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 365 -out certificate.pem
Change your app.run() method in python script to below
context = (r"{path}\certificate.pem", r"{path}\key.pem")
if __name__ == '__main__':
app.run(host='0.0.0.0',port=5000,debug=True,ssl_context=context)
path refers to the location directory where the key and certificate files are stored.

Device Orientation API not working with local webserver

While working with the Device Orientation API I noticed something strange.
The following online demo works perfectly (except for "compassneedscalibration"): https://www.audero.it/demo/device-orientation-api-demo.html
But when I clone the Soucecode locally and provide the Web page via a local Web server* the API seems to not be available anymore. Although using the same browser tab. Also no Messages, warnings or errors appear in the JavaScript console.
The Web page states:
deviceorientation event not supported
devicemotion event not supported
compassneedscalibration event not supported
Am I doing something wrong? Or is this an intended behavior or a bug?
I will need to provide my web app by a local web server.
I am using "Chrome 79.0.3945.93" on "Android 7.1.1;VNS-L21 Build/NMF26V"
*) python3 -m http.server
I found out that you need to provide the wep page via an Encrypted HTTPS connection on order to access the Device Orientation API and also some mediaDevices.
A simple way of providing HTTPS pages during development (not production) is this simple python webserver:
#!/usr/bin/env python3
# Based on http://www.piware.de/2011/01/creating-an-https-server-in-python/
# generate server.xml with the following command:
# openssl req -new -x509 -keyout key.pem -out server.pem -days 365 -nodes
# run as follows:
# python3 simple-https-server.py
# then in your browser, visit:
# https://localhost:4443
import http.server
import ssl
import os
directory_of_script = os.path.dirname(os.path.abspath(__file__))
#server_address = ('localhost', 4443)
server_address = ('', 4443)
httpd = http.server.HTTPServer(server_address, http.server.SimpleHTTPRequestHandler)
httpd.socket = ssl.wrap_socket(httpd.socket,
server_side=True,
certfile=os.path.join(directory_of_script, "server.pem") ,
keyfile=os.path.join(directory_of_script, "key.pem"),
ssl_version=ssl.PROTOCOL_TLS)
httpd.serve_forever()

How to create webhook from Google Apps Script using the "exec" url rather than "dev" url. Exec returns 403 Error

Been attempting to set-up a webhook in Google Sheets Apps Script that will respond when changes are made in Trello. To do this, it's suggested to deploy the script as a web app (requiring doGet and doPost functions that return HTML) to create a URL destination for receiving post and get requests.
The web app makes two URLs, one ends in /dev and is for development purposes (doesn't respond to post requests) and the other ends in /exec for normal access.
I've deployed the web app, both URL's are accessible and responsive in my browser (can view exec in incognito without sign-in), app is published to execute as "me" and be accessible by "anyone, even anonymous."
I have been able to successfully use the below code to create web-hooks for the /dev URL but not the /exec URL.
function create() {
var url = 'https://api.trello.com/1/tokens/ae6ebe60b45abcd2d4aa945c9ab4c4571bd6b6f7856b1df0cd387fbffc649579/webhooks/?key=a211f4aca7fb3e521d652730dd231cb6'
var payload = {
"key": "xxxxxxxxxxx",
"token" : "xxxxxxxxxxxxx",
"callbackURL": "https://script.google.com/macros/s/AKfycbw51TYGWHe95hKdcAs4l7E2eg0AtBi8e48lf_iafKYI/dev",
"idModel":"xxxxxxxx",
"description": "GW Test"
}
var options = {"method" : "post",
"payload" : payload,
"muteHttpExceptions": true
};
var response = UrlFetchApp.fetch(url,options);
}
When using the /dev URL, I can see that a new web-hook is added in my Trello, but the /exec URL returns the following error:
{"message":"URL (https://script.google.com/macros/s/AKfycbxo90ucgXXz7MG6Z3wb2KD-PJn3akGKoelXLJ2mkg/exec) did not return 200 status code, got 403","error":"ERROR"}
So Trello was expecting a "200 Status Code" returned to verify that the script ran properly, but received 403 instead. What confuses me is why this doesn't happen when using /dev? How can I get it to accept my /exec URL?
More Info:
I can get my code to respond to put and get requests when I use link or load the URL directly in my browser. It responds by filling the first six (6) cells in the spreadsheet.
I have republished as a new version and verified that the code still works, but I still get the error message from Trello saying that they received a 403 rather than 200 code. And I only receive this error when using /exec not /dev. And since /dev can't receive post requests, it isn't going to be helpful :(
Below is the remainder of an example:
function doSomething() {
var values = [11,12];
SpreadsheetApp.getActiveSheet().getRange("A1:B1").setValue(values);
}
function create() {
var url = 'https://api.trello.com/1/tokens/ae6ebe60b45abcd2d4aa945c9ab4c4571bd6b6f7856b1df0cd387fbffc649579/webhooks/?key=a211f4aca7fb3e521d652730dd231cb6'
var payload = {
"key": "xxxxxxxxxxxxxxxxxx",
"token" : "xxxxxxxxxxxxxxxxxxx": "https://script.google.com/macros/s/AKfycbw51TYGWHe95hKdcAs4l7E2eg0AtBi8e48lf_iafKYI/dev",
"idModel":"xxxxxxxxxxxxxxxxxxxxxxxx",
"description": "GW Test"
}
var options = {"method" : "delete",
"payload" : payload,
// "muteHttpExceptions": true
};
var response = UrlFetchApp.fetch(url,options); // creates webhook
}
// function that fires when the webapp receives a GET request
function doGet(e) {
doSomething();
var values = [21,22];
SpreadsheetApp.getActiveSheet().getRange("A2:B2").setValue(values);
return HtmlService.createHtmlOutput("something Get-ed");
}
function doPost(e) {
doSomething();
var values = [31,32];
SpreadsheetApp.getActiveSheet().getRange("A3:B3").setValue(values);
return ContentService.createTextOutput("something Posted");
//var params = JSON.stringify(e);
}
How about this answer?
Issue:
From your question, the following error is returned from API.
{"message":"URL (https://script.google.com/macros/s/AKfycbxo90ucgXXz7MG6Z3wb2KD-PJn3akGKoelXLJ2mkg/exec) did not return 200 status code, got 403","error":"ERROR"}
About the reason of above error, at first, I thought that the latest script might not be reflected to Web Apps. But from your reply comment, it was found that the latest script was reflected to Web Apps. From this situation, I experimented for retrieving the error of 403 from the deployed Web Apps.
Preparation:
As the preparation, Web Apps was deployed with "Execute the app as" and "Who has access to the app" as Me and Anyone, even anonymous, respectively. The sample script for Web Apps is as follows.
function doGet(e) {return ContentService.createTextOutput("GET: Done.")}
Experiment:
Using Google Apps Script:
At first, I checked the status code using Google Apps Script, when it requests to Web Apps. The script is as follows.
function myFunction() {
var url_exec = "https://script.google.com/macros/s/###/exec";
var url_dev = "https://script.google.com/macros/s/###/dev";
var res = UrlFetchApp.fetchAll([{url: url_exec}, {url: url_dev}]);
res.forEach(function(e) {
Logger.log(e.getResponseCode());
});
}
In this case, the status code of 200 was obtained for both endpoints of exec and dev. Using Google Apps Script, the status code of 403 couldn't be retrieved.
Using Curl:
In order to retrieve the status code with curl, curl -s -o /dev/null -w "%{http_code}" http://www.example.org/ is used. This is from this thread. Here, the status code was investigated using the curl command. Because the curl can access by 2 kinds of request by the options as showing below.
--include: Include the HTTP response headers in the output. The HTTP response headers can include things like server name, cookies, date of the document, HTTP version and more...
--head: (HTTP FTP FILE) Fetch the headers only! HTTP-servers feature the command HEAD which this uses to get nothing but the header of a document. When used on an FTP or FILE file, curl displays the file size and last modification time only.
Using above options, the following 4 patterns were investigated.
Request to the endpoint of exec using the option --include.
curl -sL --include -o /dev/null -w "%{http_code}" "https://script.google.com/macros/s/###/exec"
200 was returned.
Request to the endpoint of dev using the option --include.
curl -sL --include -o /dev/null -w "%{http_code}" "https://script.google.com/macros/s/###/dev"
200 was returned.
Request to the endpoint of exec using the option --head.
curl -sL --head -o /dev/null -w "%{http_code}" "https://script.google.com/macros/s/###/exec"
403 was returned.
Request to the endpoint of dev using the option --head.
curl -sL --head -o /dev/null -w "%{http_code}" "https://script.google.com/macros/s/###/dev"
200 was returned.
As the result, it was found that when the Web Apps of the endpoint of exec was requested with the option --head, the status code of 403 was obtained.
Result and discussions:
When the option --head is used for the curl command, from the document, this means that it requests only header and doesn't request the body. By this, it was found that the status code of 403 was returned.
Here, why was the status code of 200 returned for both options of --include and --head when it requests to the endpoint of dev? It is considered that the reason of this is due to that the login screen was returned. When the endpoint of dev is accessed, it is required to use the access token. When the access token is not used, the login screen is returned. In this case, the status code of 200 is returned. As the test case, when the access token is used for the endpoint of dev using below curl command,
curl -sL --head -H "Authorization: Bearer ###" -o /dev/null -w "%{http_code}" "https://script.google.com/macros/s/###/dev"
The status code of 403 was returned. From this result, the following results were obtained.
When only the header is retrieved under that the Web Apps works fine, 403 is returned.
When the login screen is returned, 200 is returned.
As the result, it is considered that the reason of error of {"message":"URL (https://script.google.com/macros/s/AKfycbxo90ucgXXz7MG6Z3wb2KD-PJn3akGKoelXLJ2mkg/exec) did not return 200 status code, got 403","error":"ERROR"} is due to above situation.
Workaround:
From above results, when the Web Apps is deployed with "Execute the app as" and "Who has access to the app" as Me and Only myself, respectively, when it requests to the endpoint of exec using the option --head, it is found that the status code of 200 will be returned. Because at this time, the login screen is displayed.
Using this situation, how about the following flow as a workaround?
When the endpoint of Web Apps is registered to the API, please deploy the Web Apps with "Execute the app as" and "Who has access to the app" as Me and Only myself, respectively.
After the registration was completed, please deploy Web Apps with "Execute the app as" and "Who has access to the app" as Me and Anyone, even anonymous, respectively.
By this, the Web Apps can be accessed.
By above flow, only when the endpoint is registered, the status code of 200 is returned. But in this workaround, it supposes that the API you want to use might check the requested header. If my guess was not correct, this workaround cannot be used. In that case, I have to apologize.
References:
Web Apps
Taking advantage of Web Apps with Google Apps Script
curl.haxx.se
Added:
In my environment, I could confirm that the endpoint of exec of Web Apps could be registered with the trello API using above workaround. The script I used is as follows.
Before you run the script, please set the Web Apps as follows.
"Execute the app as" and "Who has access to the app" are Me and Only myself, respectively.
After the response of like {"id":"###","description":"sample","idModel":"###","callbackURL":"https://script.google.com/macros/s/###/exec","active":true} was retrieved, please set the Web Apps as follows.
"Execute the app as" and "Who has access to the app" are Me and Anyone, even anonymous, respectively.
By this flow, the webhook can be used.
Sample script:
var url = 'https://api.trello.com/1/tokens/###/webhooks/?key=###'
var payload = {
"callbackURL": "https://script.google.com/macros/s/###/exec",
"idModel":"###",
"description": "sample"
}
var options = {method: "post", payload: payload};
var res = UrlFetchApp.fetch(url,options);
Logger.log(res.getContentText())

How to connect backend (python, flask) with frontend (html, css, javascript)

Info: for backend I'm using python with flask (for the moment it accepts http get methods) and for frontend I'm using html, css and javascript.
Problem: I'm trying to make a http request (first time I tried POST and then GET) but the browser did not allow me to do that: "Access to XMLHttpRequest at 'localhost:5000/test' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https.".
What another choices do I have? (I would like some simple choices, it is just a homework).
I've tried to make http POST and GET request.
I've read that I cannot make http request from browser.
I've read that I need (for example) an apache server. - too complicated, I need something more simple.
I've tried: https://flask-cors.readthedocs.io/en/latest/
document.getElementById("btn").addEventListener('click', add);
function add()
{
const url = "localhost:5000/test";
const http = new XMLHttpRequest();
http.open("GET", url);
http.send();
http.onreadystatechange=(e)=> {
console.log(http.responseText)
}
}
from flask import Flask
from flask_cors import CORS
from flask import request
from flask import jsonify
import json
import mysql.connector
import random
import string
import time
time.sleep(3)
app = Flask(__name__)
#app.route("/test")
def test():
return "It's working"
if __name__ == "__main__":
app.run(host='0.0.0.0', port=5000)
I expect that in the browser console to be printed message: "It's working", but I get the error:
Access to XMLHttpRequest at 'localhost:5000/test' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https.
LE: Flask server is inside a docker container. Ports are mapped "5000:5000'.
If you are using same machine, you do not need to use flask-cors.
Update:
As you are using Docker you can use flask-cors to handle CORS.
I found that the AJAX calls were not correct in your JS code. const url = "localhost:5000/test"; does not provide information on request protocol.
I followed these steps to run Flask application successfully using Docker and accessing the /test endpoint using JS outside Docker.
I updated AJAX request
Added Dockerfile to run Flask application inside Docker
Build and run the Dockerfile
Get the IP address of running Docker container.
Used the IP address in AJAX call in JS code which is outside Docker.
Folder structure:
.
├── backend.py
├── Dockerfile
├── readme.md
└── requirements.txt
requirements.txt:
Flask==1.0.2
Flask-Cors==3.0.7
Dockerfile:
FROM python:3
ENV PYTHONBUFFERED 1
RUN mkdir /code
WORKDIR /code
ADD requirements.txt /code/
RUN pip install -r requirements.txt
ADD . /code/
CMD ["python", "backend.py" ]
Build Docker file:
docker build -t flask-docker .
Run Docker:
docker run -p 5000:5000 flask-docker
* Serving Flask app "backend" (lazy loading)
* Environment: production
WARNING: Do not use the development server in a production environment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
Get Docker container ID:
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
69cb7d5d243a flask-docker "python backend.py" 15 minutes ago Up 15 minutes 0.0.0.0:5000->5000/tcp
Get Docker container IP address:
docker inspect --format '{{ .NetworkSettings.IPAddress }}' 69cb7d5d243a
172.17.0.2
Use this IP address in AJAX request in HTML file:
<html>
<head>
<title>Frontend</title>
</head>
<body>
<div id="data"></div>
<button type="button" id="btn">Grab data</button>
<script type="text/javascript">
document.getElementById("btn").addEventListener('click', add);
function add()
{
const api_url = "http://172.17.0.2:5000/test";
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("data").append(this.responseText);
}
};
xhttp.open("GET", api_url, true);
xhttp.send();
}
</script>
</body>
</html>
backend.py:
from flask import Flask, request, jsonify
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
#app.route("/test")
def test():
return "It's working"
if __name__ == "__main__":
app.run(host='0.0.0.0', port=5000)
Output:
Add the following line below app = Flask(__name__):
CORS(app)
Check out flask-cors simple usage

How to programmatically test if ngrok is already running

We have ran ngrok on a localhost PORT say http://localhost:4000. We can manually test if the ngrok is already runing or not by using the following steps:
Check if ngrok is already running:
Hit http://127.0.0.1:4040/status
If the connection happens successfully, the following visual will show up:
If the above visual is not showing, ngrok is not running at all.
Under Tunnels section, the following visual will show up:
If the above visual is not showing, ngrok is not running on PORT 4000.
To start ngrok on http://localhost:4000, we need to run ngrok http 4000. After running this command, the above visuals will show up.
Is there some programmatic way to determine if ngrok is already running on the port?
For others stumbling by this question,
Make a request to http://localhost:4040/api/tunnels using curl or any request library in the programming language of your choice. It returns a JSON formatted response of the ngrok tunnels and their urls, which you can obtain.. If it does not return anything, it means ngrok is not running
Eg for python:
import requests
import json
from bs4 import BeautifulSoup
req = requests.get('http://127.0.0.1:4040/api/tunnels')
soup = BeautifulSoup(req.text, 'lxml')
tunnelsjson = json.loads(soup.find('p').text)
url = tunnelsjson['tunnels'][0]['public_url']
print(url)
Run this command to see using ports:
sudo lsof -PiTCP -sTCP:LISTEN
You can check it by python:
import socket;
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
result = sock.connect_ex(('127.0.0.1',4000))
print(result)
if result == 0:
print "Port is not open"
else:
print "Port is open"
P.S. if port is in use, result is 0, if not it is 61.
Run netstat -tulnap | grep ngrok
netstat -tulnap shows which processes are running on the machine
grep ngrok filters for the ngrok processes.

Categories