remove jwt
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Torma Kristóf 2020-11-26 01:27:33 +01:00
parent 6e3ba36851
commit 34bb3fcc25
7 changed files with 82 additions and 64 deletions

14
docker-compose.yml Normal file
View File

@ -0,0 +1,14 @@
version: '3'
networks:
redis:
external: false
services:
db:
image: redis
restart: always
ports:
- "127.0.0.1:6379:6379"
networks:
- redis

View File

@ -2,7 +2,6 @@ musicbrainzngs
flask flask
flask-restful flask-restful
gunicorn gunicorn
flask-jwt-extended
sentry-sdk[flask] sentry-sdk[flask]
py-healthcheck py-healthcheck
flask-redis flask-redis

View File

@ -10,48 +10,48 @@ __module_name__ = "aes_encrypt"
__version__text__ = "1" __version__text__ = "1"
import base64 import base64
import json import pickle
from Crypto.Cipher import AES from Crypto.Cipher import AES
from fred import flaskred from fred import flaskred
from schemas import UserSchema
class AESCrypto: class AESCrypto:
def __init__(self, encoded_secret_key: str, padding_character: bytes = 'a'.encode('UFT-8')): def __init__(self, encoded_secret_key: str, padding_character: bytes = '{'.encode('ascii')):
self.padding_character = padding_character self.padding_character = padding_character
self.encoded_secret_key = encoded_secret_key self.encoded_secret_key = encoded_secret_key
def encrypt_message(self, private_msg) -> bytes: def encrypt_message(self, private_msg: str) -> tuple:
secret_key = base64.b64decode(self.encoded_secret_key) secret_key = base64.b64decode(self.encoded_secret_key)
cipher = AES.new(secret_key, AES.MODE_EAX) cipher = AES.new(secret_key, AES.MODE_EAX)
padded_private_msg = private_msg + (self.padding_character.decode('UFT-8') * ((16 - len(private_msg)) % 16)) ciphertext, tag = cipher.encrypt_and_digest(private_msg.encode('UTF-8'))
encrypted_msg = cipher.encrypt(padded_private_msg) return cipher.nonce, ciphertext, tag
encoded_encrypted_msg = base64.b64encode(encrypted_msg)
return encoded_encrypted_msg
def decrypt_message(self, encoded_encrypted_msg) -> str: def decrypt_message(self, nonce: bytes, encoded_encrypted_msg: bytes, tag: bytes) -> str:
secret_key = base64.b64decode(self.encoded_secret_key) secret_key = base64.b64decode(self.encoded_secret_key)
encrypted_msg = base64.b64decode(encoded_encrypted_msg) cipher = AES.new(secret_key, AES.MODE_EAX, nonce)
cipher = AES.new(secret_key, AES.MODE_EAX) msg = cipher.decrypt_and_verify(encoded_encrypted_msg, tag).decode('UTF-8')
decrypted_msg = cipher.decrypt(encrypted_msg) return msg
unpadded_private_msg = decrypted_msg.rstrip(self.padding_character)
return unpadded_private_msg.decode('UTF-8')
class EncryptedUserRedis: class EncryptedUserRedis:
def __init__(self, encoded_secret_key: str): def __init__(self, encoded_secret_key: str):
self.aes = AESCrypto(encoded_secret_key) self.aes = AESCrypto(encoded_secret_key)
self.userschema = UserSchema(many=False)
def store(self, user: UserSchema) -> None: def store(self, user: dict) -> None:
plaindict = self.userschema.dump(user) nonce, ciphertext, tag = self.aes.encrypt_message(user['password'])
plaindict['password'] = self.aes.encrypt_message(user['password']) user['nonce'] = nonce
flaskred.set(user['name'], json.dumps(plaindict).encode('UTF-8')) user['ciphertext'] = ciphertext
user['tag'] = tag
user.pop('password', None)
flaskred.set(user['name'], pickle.dumps(user))
def load(self, username: str) -> UserSchema: def load(self, username: str) -> dict:
encryptedstr = flaskred.get(username).decode('UTF-8') encrypteddict = pickle.loads(flaskred.get(username))
encrypteddict = json.loads(encryptedstr)
user = UserSchema(name=encrypteddict['name'], password=self.aes.decrypt_message(encrypteddict['password'])) plaindict = {"name": encrypteddict['name'],
return user "password": self.aes.decrypt_message(encrypteddict['nonce'], encrypteddict['ciphertext'],
encrypteddict['tag'])}
return plaindict

View File

@ -1,19 +1,17 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import os
import logging import logging
from flask import Flask from flask import Flask
from flask_restful import Api from flask_restful import Api
import sentry_sdk import sentry_sdk
from sentry_sdk.integrations.flask import FlaskIntegration from sentry_sdk.integrations.flask import FlaskIntegration
from sentry_sdk.integrations.sqlalchemy import SqlalchemyIntegration
from healthcheck import HealthCheck from healthcheck import HealthCheck
from jwtman import jwtman
from marshm import ma from marshm import ma
from fred import flaskred from fred import flaskred
from config import SENTRY_DSN, JWT_SECRET_KEY, RELEASEMODE, RELEASE_ID, PORT, DEBUG, REDIS_URL from config import SENTRY_DSN, RELEASEMODE, RELEASE_ID, PORT, DEBUG, REDIS_HOST
from errorhandlers import register_all_error_handlers from errorhandlers import register_all_error_handlers
from resources import LoginApi from resources import LoginApi, LogoffApi, MeApi
""" """
Main Flask RESTful API Main Flask RESTful API
@ -27,7 +25,7 @@ __version__text__ = "1"
if SENTRY_DSN: if SENTRY_DSN:
sentry_sdk.init( sentry_sdk.init(
dsn=SENTRY_DSN, dsn=SENTRY_DSN,
integrations=[FlaskIntegration(), SqlalchemyIntegration()], integrations=[FlaskIntegration()],
traces_sample_rate=1.0, traces_sample_rate=1.0,
send_default_pii=True, send_default_pii=True,
release=RELEASE_ID, release=RELEASE_ID,
@ -36,13 +34,13 @@ if SENTRY_DSN:
) )
app = Flask(__name__) app = Flask(__name__)
app.config['JWT_SECRET_KEY'] = JWT_SECRET_KEY app.config['JWT_BLACKLIST_ENABLED'] = True
app.config['REDIS_URL'] = REDIS_URL app.config['JWT_BLACKLIST_TOKEN_CHECKS'] = ['access', 'refresh']
app.config['REDIS_URL'] = f"redis://{REDIS_HOST}:6379/0"
api = Api(app) api = Api(app)
health = HealthCheck() health = HealthCheck()
ma.init_app(app) ma.init_app(app)
flaskred.init_app(app) flaskred.init_app(app)
jwtman.init_app(app)
formatter = logging.Formatter( formatter = logging.Formatter(
fmt="%(asctime)s - %(levelname)s - %(module)s - %(message)s" fmt="%(asctime)s - %(levelname)s - %(module)s - %(message)s"
@ -58,18 +56,17 @@ logger.addHandler(handler)
api.add_resource(LogoffApi, '/api/auth/logoff') api.add_resource(LogoffApi, '/api/auth/logoff')
api.add_resource(LoginApi, '/api/auth/login') api.add_resource(LoginApi, '/api/auth/login')
api.add_resource(MeApi, '/api/auth/me') api.add_resource(MeApi, '/api/auth/me')
api.add_resource(ListsApi, '/api/lists') # api.add_resource(ListsApi, '/api/lists')
api.add_resource(SingleListApi, '/api/lists/<listid>') # api.add_resource(SingleListApi, '/api/lists/<listid>')
api.add_resource(TrackApi, '/api/lists/<listid>/<trackid>') # api.add_resource(TrackApi, '/api/lists/<listid>/<trackid>')
app.add_url_rule("/healthz", "healthcheck", view_func=lambda: health.run()) app.add_url_rule("/healthz", "healthcheck", view_func=lambda: health.run())
register_all_error_handlers(app) register_all_error_handlers(app)
if __name__ == "__main__": if __name__ == "__main__":
app.run( app.run(
debug=bool(DEBUG), debug=bool(DEBUG),
host="0.0.0.0", host="0.0.0.0",
port=int(PORT), port=int(PORT),
) )

View File

@ -1,6 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import os import os
from uuid import uuid4
""" """
Configuration Configuration
@ -20,8 +19,6 @@ SENTRY_DSN = os.environ.get("SENTRY_DSN")
RELEASE_ID = os.environ.get("RELEASE_ID", "test") RELEASE_ID = os.environ.get("RELEASE_ID", "test")
RELEASEMODE = os.environ.get("ONSPOT_RELEASEMODE", "dev") RELEASEMODE = os.environ.get("ONSPOT_RELEASEMODE", "dev")
JWT_SECRET_KEY = os.getenv("ONSPOT_JWT_SECRET_KEY", str(uuid4())) REDIS_HOST = os.getenv("ONSPOT_REDIS_HOST")
REDIS_URL = os.getenv("ONSPOT_REDIS_URL")
ENCODED_SECRET_KEY = os.getenv("ONSPOT_ENCODED_SECRET_KEY") ENCODED_SECRET_KEY = os.getenv("ONSPOT_ENCODED_SECRET_KEY")

View File

@ -1,14 +0,0 @@
#!/usr/bin/env python3
from flask_jwt_extended import JWTManager
"""
JWTManager
"""
__author__ = '@tormakris'
__copyright__ = "Copyright 2020, onSpot Team"
__module_name__ = "jwtman"
__version__text__ = "1"
jwtman = JWTManager()

View File

@ -1,10 +1,11 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import datetime
from flask_jwt_extended import create_access_token, jwt_required, get_jwt_identity import uuid
from flask_restful import Resource from flask_restful import Resource
from flask import request, current_app, abort from flask import request, current_app, abort, request
from fred import flaskred
from config import ENCODED_SECRET_KEY from config import ENCODED_SECRET_KEY
from schemas import UserSchema, ListSchema, TrackSchema from schemas import UserSchema, ListSchema, TrackSchema
from aes_encrypt import EncryptedUserRedis from aes_encrypt import EncryptedUserRedis
@ -38,8 +39,32 @@ class LoginApi(Resource):
current_app.logger.warning(e) current_app.logger.warning(e)
abort(417, INVALID_JSON_SCHEMA_MSG) abort(417, INVALID_JSON_SCHEMA_MSG)
self.encryptor.store(userobj) self.encryptor.store(body)
expires = datetime.timedelta(days=7) token = str(uuid.uuid4())
access_token = create_access_token(identity=str(userobj['name']), expires_delta=expires)
return {'token': access_token}, 200 flaskred.set(token, userobj['name'].encode('UTF-8'))
return {
'token': token
}, 200
class LogoffApi(Resource):
"""
See: https://swagger.kmlabz.com/?urls.primaryName=onSpot%20Backend#/backend/logoff
"""
def delelete(self):
flaskred.delete(flaskred.get(request.headers.get('Authorization')).decode('UTF-8'))
flaskred.delete(request.headers.get('Authorization'))
return 204
class MeApi(Resource):
"""
See: https://swagger.kmlabz.com/?urls.primaryName=onSpot%20Backend#/backend/currentUser
"""
def get(self):
return {"name": flaskred.get(request.headers.get('Authorization')).decode('UTF-8')}, 200