Added SSL capabilities to the webapp
This commit is contained in:
parent
ea0393801f
commit
8145769b7a
4 changed files with 151 additions and 4 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -142,4 +142,6 @@ cython_debug/
|
|||
secrets.txt
|
||||
messages.txt
|
||||
Vagrantfile
|
||||
.vagrant
|
||||
.vagrant
|
||||
cert.pem
|
||||
key.pem
|
||||
|
|
@ -46,6 +46,12 @@ parser.add_argument('-i', '--ip', required=False, default="0.0.0.0", type=str,
|
|||
help="""Specifies the IP to run the webapp at. Defaults to 0.0.0.0""")
|
||||
parser.add_argument('-p', '--port', required=False, default=8000, type=int,
|
||||
help="""Specifies the port to run the webapp at. Defaults to 8000""")
|
||||
parser.add_argument('--usessl', required=False, default=False, action='store_true',
|
||||
help="""Enables or disables SSL use in the webapp""")
|
||||
parser.add_argument('--certpath', required=False, default=None, type=str,
|
||||
help="""Specifies the folder location for SSL certificates used
|
||||
in the webapp. Certificates in this folder should be in the form of
|
||||
a 'cert.pem' and 'key.pem' pair.""")
|
||||
args = parser.parse_args()
|
||||
|
||||
|
||||
|
|
@ -313,7 +319,8 @@ def main():
|
|||
|
||||
if args.command == 'webapp':
|
||||
from .web import start_web_app
|
||||
start_web_app(ip=args.ip, port=args.port)
|
||||
start_web_app(ip=args.ip, port=args.port,
|
||||
usessl=args.usessl, cert_path=args.certpath)
|
||||
elif args.command == 'demo':
|
||||
demo()
|
||||
elif args.command == 'macro':
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
import json
|
||||
import os
|
||||
from threading import RLock
|
||||
import time
|
||||
|
||||
from .cert import generate_cert
|
||||
from ..nxbt import Nxbt, PRO_CONTROLLER
|
||||
from flask import Flask, render_template, request
|
||||
from flask_socketio import SocketIO, emit
|
||||
|
|
@ -88,6 +90,7 @@ def on_create_controller():
|
|||
|
||||
@sio.on('input')
|
||||
def handle_input(message):
|
||||
# print("Webapp Input", time.perf_counter())
|
||||
message = json.loads(message)
|
||||
index = message[0]
|
||||
input_packet = message[1]
|
||||
|
|
@ -102,8 +105,55 @@ def handle_macro(message):
|
|||
nxbt.macro(index, macro)
|
||||
|
||||
|
||||
def start_web_app(ip='0.0.0.0', port=8000):
|
||||
eventlet.wsgi.server(eventlet.listen((ip, port)), app)
|
||||
def start_web_app(ip='0.0.0.0', port=8000, usessl=False, cert_path=None):
|
||||
if usessl:
|
||||
if cert_path is None:
|
||||
# Store certs in the package directory
|
||||
cert_path = os.path.join(
|
||||
os.path.dirname(__file__), "cert.pem"
|
||||
)
|
||||
key_path = os.path.join(
|
||||
os.path.dirname(__file__), "key.pem"
|
||||
)
|
||||
else:
|
||||
# If specified, store certs at the user's preferred location
|
||||
cert_path = os.path.join(
|
||||
cert_path, "cert.pem"
|
||||
)
|
||||
key_path = os.path.join(
|
||||
cert_path, "key.pem"
|
||||
)
|
||||
if not os.path.isfile(cert_path) or not os.path.isfile(key_path):
|
||||
print(
|
||||
"\n"
|
||||
"-----------------------------------------\n"
|
||||
"---------------->WARNING<----------------\n"
|
||||
"The NXBT webapp is being run with self-\n"
|
||||
"signed SSL certificates for use on your\n"
|
||||
"local network.\n"
|
||||
"\n"
|
||||
"These certificates ARE NOT safe for\n"
|
||||
"production use. Please generate valid\n"
|
||||
"SSL certificates if you plan on using the\n"
|
||||
"NXBT webapp anywhere other than your own\n"
|
||||
"network.\n"
|
||||
"-----------------------------------------\n"
|
||||
"\n"
|
||||
"The above warning will only be shown once\n"
|
||||
"on certificate generation."
|
||||
"\n"
|
||||
)
|
||||
print("Generating certificates...")
|
||||
cert, key = generate_cert('localhost')
|
||||
with open(cert_path, "wb") as f:
|
||||
f.write(cert)
|
||||
with open(key_path, "wb") as f:
|
||||
f.write(key)
|
||||
|
||||
eventlet.wsgi.server(eventlet.wrap_ssl(eventlet.listen((ip, port)),
|
||||
certfile=cert_path, keyfile=key_path), app)
|
||||
else:
|
||||
eventlet.wsgi.server(eventlet.listen((ip, port)), app)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
88
nxbt/web/cert.py
Normal file
88
nxbt/web/cert.py
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
# Copyright 2018 Simon Davy
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
# WARNING: the code in the gist generates self-signed certs, for the purposes of testing in development.
|
||||
# Do not use these certs in production, or You Will Have A Bad Time.
|
||||
#
|
||||
# Caveat emptor
|
||||
#
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
import ipaddress
|
||||
|
||||
from cryptography import x509
|
||||
from cryptography.x509.oid import NameOID
|
||||
from cryptography.hazmat.primitives import hashes
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from cryptography.hazmat.primitives import serialization
|
||||
from cryptography.hazmat.primitives.asymmetric import rsa
|
||||
|
||||
def generate_cert(hostname, ip_addresses=None, key=None):
|
||||
"""Generates self signed certificate for a hostname, and optional IP addresses."""
|
||||
|
||||
# Generate our key
|
||||
if key is None:
|
||||
key = rsa.generate_private_key(
|
||||
public_exponent=65537,
|
||||
key_size=2048,
|
||||
backend=default_backend(),
|
||||
)
|
||||
|
||||
name = x509.Name([
|
||||
x509.NameAttribute(NameOID.COMMON_NAME, hostname)
|
||||
])
|
||||
|
||||
# best practice seem to be to include the hostname in the SAN, which *SHOULD* mean COMMON_NAME is ignored.
|
||||
alt_names = [x509.DNSName(hostname)]
|
||||
|
||||
# allow addressing by IP, for when you don't have real DNS (common in most testing scenarios
|
||||
if ip_addresses:
|
||||
for addr in ip_addresses:
|
||||
# openssl wants DNSnames for ips...
|
||||
alt_names.append(x509.DNSName(addr))
|
||||
# ... whereas golang's crypto/tls is stricter, and needs IPAddresses
|
||||
# note: older versions of cryptography do not understand ip_address objects
|
||||
alt_names.append(x509.IPAddress(ipaddress.ip_address(addr)))
|
||||
|
||||
san = x509.SubjectAlternativeName(alt_names)
|
||||
|
||||
# path_len=0 means this cert can only sign itself, not other certs.
|
||||
basic_contraints = x509.BasicConstraints(ca=True, path_length=0)
|
||||
now = datetime.utcnow()
|
||||
cert = (
|
||||
x509.CertificateBuilder()
|
||||
.subject_name(name)
|
||||
.issuer_name(name)
|
||||
.public_key(key.public_key())
|
||||
.serial_number(1000)
|
||||
.not_valid_before(now - timedelta(days=10*365))
|
||||
.not_valid_after(now - timedelta(days=9*365))
|
||||
.add_extension(basic_contraints, False)
|
||||
.add_extension(san, False)
|
||||
.sign(key, hashes.SHA256(), default_backend())
|
||||
)
|
||||
cert_pem = cert.public_bytes(encoding=serialization.Encoding.PEM)
|
||||
key_pem = key.private_bytes(
|
||||
encoding=serialization.Encoding.PEM,
|
||||
format=serialization.PrivateFormat.TraditionalOpenSSL,
|
||||
encryption_algorithm=serialization.NoEncryption(),
|
||||
)
|
||||
|
||||
return cert_pem, key_pem
|
||||
Loading…
Add table
Add a link
Reference in a new issue