Skip to content

Commit

Permalink
improved security
Browse files Browse the repository at this point in the history
  • Loading branch information
cekk committed Dec 29, 2019
1 parent 8b4e878 commit ef7d0f9
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 33 deletions.
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@ buildout:
dev:
pipenv run python app.py

dev-ssl:
pipenv run python app.py --cert /Users/cekk/letsencrypt/config/live/cekk.changeip.co/fullchain.pem --key /Users/cekk/letsencrypt/config/live/cekk.changeip.co/privkey.pem

prod:
pipenv run gunicorn -c gunicorn_config.py wsgi:app
bin/gunicorn -c gunicorn_config.py wsgi:app

deploy_lambda:
pipenv run pip install --target ./lambda_function/package -r lambda_function/requirements.txt
Expand Down
77 changes: 54 additions & 23 deletions app.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,35 @@
from flask import Flask, render_template, send_from_directory
from flask_restful import Resource, Api, reqparse
# -*- coding: utf-8 -*-
from flask import Blueprint
from flask import Flask
from flask import Flask
from flask import render_template
from flask import request
from flask import send_from_directory
from flask_mqtt import Mqtt
from flask_restful import Resource, Api, reqparse, abort
from flask_socketio import SocketIO
from utils import createSocketMessage

from flask_jwt_extended import (
JWTManager,
jwt_required,
create_access_token,
get_jwt_identity,
)
from functools import wraps
import logging
import os
import re

app = Flask(
__name__, instance_relative_config=True, static_folder="static/build"
)
app = Flask(__name__, instance_relative_config=True, static_folder="static/build")
app.config.from_pyfile("config.py")

api = Api(app)
api_bp = Blueprint("api", __name__)
api = Api(api_bp)
app.register_blueprint(api_bp)

socketio = SocketIO(app)
mqtt = Mqtt(app)
jwt = JWTManager(app)

parser = reqparse.RequestParser()
parser.add_argument("command", type=str, help="")
Expand All @@ -25,9 +40,7 @@ def handle_connect(client, userdata, flags, rc):
# mqtt.subscribe("shellies/command")
for blind in app.config.get("BLINDS", []):
mqtt.subscribe("shellies/{id}/online".format(id=blind.get("id", "")))
mqtt.subscribe(
"shellies/{id}/roller/0/pos".format(id=blind.get("id", ""))
)
mqtt.subscribe("shellies/{id}/roller/0/pos".format(id=blind.get("id", "")))
mqtt.subscribe("shellies/{id}/roller/0".format(id=blind.get("id", "")))


Expand All @@ -47,17 +60,33 @@ def connect_handler():
mqtt.publish("shellies/command", "announce")


@app.route("/", defaults={"path": ""})
@app.route("/<path:path>")
def serve(path):
if path != "" and os.path.exists(app.static_folder + "/" + path):
return send_from_directory(app.static_folder, path)
else:
return send_from_directory(app.static_folder, "index.html")
# @app.route("/", defaults={"path": ""})
# @app.route("/<path:path>")
# def serve(path):
# if path != "" and os.path.exists(app.static_folder + "/" + path):
# return send_from_directory(app.static_folder, path)
# else:
# app.logger.info("AAAA")
# app.logger.debug("BBB")
# app.logger.warning("CCC")
# app.logger.error("DDD")
# return send_from_directory(app.static_folder, "index.html")


class ProtectedResource(Resource):
method_decorators = [jwt_required]

def check_skill_id(*args, **kwargs):
if not app.config["SKILL_ID"]:
abort(401)
skill_id = get_jwt_identity()
if skill_id != app.config["SKILL_ID"]:
abort(401)


class Blinds(Resource):
class Blinds(ProtectedResource):
def get(self):
self.check_skill_id()
return app.config.get("BLINDS", [])


Expand All @@ -75,16 +104,15 @@ def get(self):
return "", 204


class Action(Resource):
class Action(ProtectedResource):
def publish(self, id, action):
mqtt.publish("shellies/{id}/roller/0/command".format(id=id), action)

def get(self, id, action):
self.check_skill_id()
if action not in ["close", "open", "stop"]:
return (
{
"message": 'Valid actions are "close", "open", "stop" or "rc"'
},
{"message": 'Valid actions are "close", "open", "stop" or "rc"'},
400,
)
if id == "all":
Expand All @@ -109,4 +137,7 @@ def get(self, id, action):
api.add_resource(Action, "/roller/<string:id>/<string:action>")

if __name__ == "__main__":
socketio.run(app, debug=True, host="0.0.0.0", threaded=False)
gunicorn_logger = logging.getLogger("gunicorn.error")
app.logger.handlers = gunicorn_logger.handlers
app.logger.setLevel(gunicorn_logger.level)
socketio.run(app, debug=True, host="0.0.0.0", port=4000)
1 change: 1 addition & 0 deletions flask.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ eggs =
gunicorn
flask-socketio
gevent
flask_jwt_extended
29 changes: 21 additions & 8 deletions lambda_function/lambda_function.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@

import boto3
import json
import requests
import jwt
import os
import requests

api_endpoint = os.environ["API_ENDPOINT"]
skill_id = os.environ["SKILL_ID"]
token_secret = os.environ["TOKEN_SECRET"]


def lambda_handler(request, context):
Expand Down Expand Up @@ -61,7 +64,7 @@ def lambda_handler(request, context):

if namespace == "Alexa.Discovery":
if name == "Discover":
res = requests.get("{}/blinds".format(api_endpoint))
res = call_api(endpoint="blinds")

adr = AlexaResponse(namespace="Alexa.Discovery", name="Discover.Response")
capability_alexa = adr.create_payload_endpoint_capability()
Expand Down Expand Up @@ -119,18 +122,17 @@ def lambda_handler(request, context):
# Note: This sample always returns a success response for either a request to TurnOff or TurnOn
device_id = request["directive"]["endpoint"]["endpointId"]
action = "close" if name == "TurnOff" else "open"
print(">>>>> NAME: {}".format(name))
print(request)
res = requests.get(
"{api_endpoint}/roller/{device_id}/{action}".format(
api_endpoint=api_endpoint, device_id=device_id, action=action
call_api(
endpoint="roller/{device_id}/{action}".format(
device_id=device_id, action=action
)
)
correlation_token = request["directive"]["header"]["correlationToken"]

apcr = AlexaResponse(correlation_token=correlation_token)
state_value = "OFF" if name == "TurnOff" else "ON"
apcr.add_context_property(
namespace="Alexa.ToggleController", name="toggleState", value="ciccio",
namespace="Alexa.ToggleController", name="toggleState", value=state_value,
)
return send_response(apcr.get())

Expand All @@ -141,3 +143,14 @@ def send_response(response):
print(json.dumps(response))
return response


def call_api(endpoint):
auth_token = jwt.encode({"identity": skill_id}, token_secret, algorithm="HS256")
hed = {"Authorization": b"Bearer " + auth_token}
url = "{api_endpoint}/{endpoint}".format(
api_endpoint=api_endpoint, endpoint=endpoint
)
print("lambda_handler CALL API -----")
print(url)
requests.get(url, headers=hed)

3 changes: 2 additions & 1 deletion lambda_function/requirements.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
requests
requests
pyjwt

0 comments on commit ef7d0f9

Please sign in to comment.