Fix: User login on production.
This commit is contained in:
6
app.py
6
app.py
@@ -96,10 +96,12 @@ def internal_server_error(error):
|
||||
app.logger.error('Traceback: %s', traceback.format_exc())
|
||||
return "Internal Server Error", 500
|
||||
|
||||
@app.before_request
|
||||
def make_session_permanent():
|
||||
session.permanent = True
|
||||
|
||||
|
||||
"""
|
||||
csrf = CSRFProtect()
|
||||
"""
|
||||
cors = CORS()
|
||||
db = SQLAlchemy()
|
||||
mail = Mail()
|
||||
|
||||
15
config.py
15
config.py
@@ -32,6 +32,15 @@ class Config:
|
||||
SQLALCHEMY_DATABASE_URI = os.getenv('SQLALCHEMY_DATABASE_URI')
|
||||
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
||||
# Auth0
|
||||
SESSION_COOKIE_SECURE = True
|
||||
SESSION_COOKIE_HTTPONLY = True
|
||||
# SESSION_COOKIE_SAMESITE = 'Lax'
|
||||
# PERMANENT_SESSION_LIFETIME = 3600
|
||||
WTF_CSRF_ENABLED = True
|
||||
# WTF_CSRF_CHECK_DEFAULT = False # We'll check it manually for API routes
|
||||
# WTF_CSRF_HEADERS = ['X-CSRFToken'] # Accept CSRF token from this header
|
||||
WTF_CSRF_TIME_LIMIT = None
|
||||
WTF_CSRF_SSL_STRICT = False # Allows testing without HTTPS
|
||||
ID_AUTH0_CLIENT = os.getenv('ID_AUTH0_CLIENT')
|
||||
ID_AUTH0_CLIENT_SECRET = os.getenv('ID_AUTH0_CLIENT_SECRET')
|
||||
DOMAIN_AUTH0 = os.getenv('DOMAIN_AUTH0')
|
||||
@@ -71,9 +80,10 @@ class Config:
|
||||
|
||||
class DevelopmentConfig(Config):
|
||||
is_development = True
|
||||
# Add development-specific configuration variables
|
||||
DEBUG = True
|
||||
MAIL_DEBUG = True
|
||||
# Add development-specific configuration variables
|
||||
SESSION_COOKIE_SECURE = False
|
||||
|
||||
class ProductionConfig(Config):
|
||||
is_production = True
|
||||
@@ -82,8 +92,9 @@ class ProductionConfig(Config):
|
||||
|
||||
# Set the configuration class based on the environment
|
||||
# You can change 'development' to 'production' when deploying
|
||||
config_env = os.getenv('FLASK_ENV', "production")
|
||||
config_env = os.getenv('FLASK_ENV', "development")
|
||||
with open('app.log', 'a') as f:
|
||||
print(f'config_env: {config_env}')
|
||||
f.write(f'config_env: {config_env}\n')
|
||||
# current_app.logger.error(f'config_env: {config_env}') # logger not yet initialised
|
||||
if config_env == 'development':
|
||||
|
||||
Binary file not shown.
@@ -21,24 +21,59 @@ import lib.argument_validation as av
|
||||
# external
|
||||
from flask import Flask, render_template, jsonify, request, render_template_string, send_from_directory, redirect, url_for, session, Blueprint, current_app
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
from flask_wtf.csrf import generate_csrf
|
||||
from werkzeug.exceptions import BadRequest
|
||||
from extensions import oauth # db,
|
||||
from urllib.parse import quote_plus, urlencode
|
||||
from authlib.integrations.flask_client import OAuth
|
||||
from authlib.integrations.base_client import OAuthError
|
||||
from urllib.parse import quote, urlparse, parse_qs
|
||||
from functools import wraps
|
||||
|
||||
db = SQLAlchemy()
|
||||
|
||||
routes_user = Blueprint('routes_user', __name__)
|
||||
|
||||
# User authentication
|
||||
@routes_user.route("/login", methods=['POST'])
|
||||
@routes_user.route("/login", methods=['POST', 'OPTIONS'])
|
||||
def login():
|
||||
Helper_App.console_log('login')
|
||||
Helper_App.console_log(f'method={request.method}')
|
||||
"""
|
||||
if request.method == 'OPTIONS':
|
||||
# Handle preflight request
|
||||
response = current_app.make_default_options_response()
|
||||
response.headers['Access-Control-Allow-Headers'] = f'Content-Type, {Model_View_Base.FLAG_CSRF_TOKEN}'
|
||||
response.headers['Access-Control-Allow-Methods'] = 'POST, OPTIONS'
|
||||
return response
|
||||
"""
|
||||
try:
|
||||
data = request.json
|
||||
try:
|
||||
data = request.get_json()
|
||||
except:
|
||||
data = {}
|
||||
except:
|
||||
data = {}
|
||||
Helper_App.console_log(f'data={data}')
|
||||
hash_callback = data.get(Model_View_Base.FLAG_CALLBACK, Model_View_Base.HASH_PAGE_HOME)
|
||||
Helper_App.console_log(f'hash_callback: {hash_callback}')
|
||||
|
||||
"""
|
||||
# Verify CSRF token manually
|
||||
Helper_App.console_log(f'request headers={request.headers}')
|
||||
token = request.headers.get(Model_View_Base.FLAG_CSRF_TOKEN)
|
||||
Helper_App.console_log(f'token={token}')
|
||||
Helper_App.console_log(f'session={session}')
|
||||
Helper_App.console_log(f'session token={session.get('csrf_token')}')
|
||||
if not token or token != session.get('csrf_token'):
|
||||
token = data.get(Model_View_Base.FLAG_CSRF_TOKEN, None)
|
||||
Helper_App.console_log(f'token={token}')
|
||||
if not token or token != session.get('csrf_token'):
|
||||
raise BadRequest('Invalid or missing CSRF token')
|
||||
"""
|
||||
# OAuth login
|
||||
try:
|
||||
# callback_login = F'{Model_View_Base.HASH_CALLBACK_LOGIN}{data.get(Model_View_Base.FLAG_CALLBACK, Model_View_Base.HASH_PAGE_HOME)}'
|
||||
|
||||
# encoded_path = quote(data.get(Model_View_Base.FLAG_CALLBACK, Model_View_Base.HASH_PAGE_HOME))
|
||||
@@ -46,8 +81,8 @@ def login():
|
||||
|
||||
# uri_redirect = f'{current_app.URL_HOST}/login_callback?subpath={data.get(Model_View_Base.FLAG_CALLBACK, Model_View_Base.HASH_PAGE_HOME)}'
|
||||
Helper_App.console_log(f'redirect uri: {uri_redirect}')
|
||||
hash_callback = data.get(Model_View_Base.FLAG_CALLBACK, Model_View_Base.HASH_PAGE_HOME)
|
||||
Helper_App.console_log(f'hash_callback: {hash_callback}')
|
||||
|
||||
Helper_App.console_log(f'Before red')
|
||||
|
||||
red = oauth.auth0.authorize_redirect(
|
||||
redirect_uri = uri_redirect,
|
||||
@@ -68,6 +103,11 @@ def login():
|
||||
""")
|
||||
return jsonify({'Success': True, Model_View_Base.FLAG_STATUS: Model_View_Base.FLAG_SUCCESS, f'{Model_View_Base.FLAG_CALLBACK}': headers})
|
||||
|
||||
return jsonify({'status': 'success', 'redirect': callback})
|
||||
except Exception as e:
|
||||
return jsonify({'status': 'error', 'message': str(e)}), 400
|
||||
|
||||
|
||||
@routes_user.route("/login_callback") # <path:subpath>/<code>
|
||||
def login_callback():
|
||||
try:
|
||||
|
||||
Binary file not shown.
@@ -71,6 +71,7 @@ class Model_View_Base(BaseModel, ABC):
|
||||
FLAG_CONTAINER_ICON_AND_LABEL: ClassVar[str] = 'container-icon-label'
|
||||
FLAG_CONTAINER_INPUT: ClassVar[str] = FLAG_CONTAINER + '-input'
|
||||
FLAG_COUNTY: ClassVar[str] = Base.FLAG_COUNTY
|
||||
FLAG_CSRF_TOKEN: ClassVar[str] = 'X-CSRFToken'
|
||||
FLAG_CURRENCY: ClassVar[str] = 'currency'
|
||||
FLAG_DATA: ClassVar[str] = 'data'
|
||||
FLAG_DATE_FROM: ClassVar[str] = Base.FLAG_DATE_FROM
|
||||
|
||||
44
static/dist/js/main.bundle.js
vendored
44
static/dist/js/main.bundle.js
vendored
File diff suppressed because one or more lines are too long
@@ -4,21 +4,25 @@ import DOM from './dom.js';
|
||||
export default class API {
|
||||
|
||||
static getCsrfToken() {
|
||||
// return document.querySelectorAll('meta[name=' + nameCSRFToken + ']').getAttribute('content');
|
||||
return document.querySelector(idCSRFToken).getAttribute('content');
|
||||
}
|
||||
|
||||
static async request(hashEndpoint, method = 'GET', data = null, params = null) {
|
||||
const url = API.getUrlFromHash(hashEndpoint, params);
|
||||
const csrfToken = API.getCsrfToken();
|
||||
const options = {
|
||||
method,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRFToken': API.getCsrfToken()
|
||||
[flagCsrfToken]: csrfToken,
|
||||
}
|
||||
};
|
||||
|
||||
if (data && (method === 'POST' || method === 'PUT' || method === 'PATCH')) {
|
||||
data = {
|
||||
...data,
|
||||
[flagCsrfToken]: csrfToken,
|
||||
};
|
||||
options.body = JSON.stringify(data);
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
}
|
||||
</script>
|
||||
<meta name="yandex-verification" content="4693a824cfda082a" />
|
||||
<meta id="{{ model.ID_CSRF_TOKEN }}" name="{{ model.NAME_CSRF_TOKEN }}" content="{{ csrf_token() }}" />
|
||||
<meta id="{{ model.ID_CSRF_TOKEN }}" name="{{ model.FLAG_CSRF_TOKEN }}" content="{{ csrf_token() }}" />
|
||||
|
||||
<!-- Scripts
|
||||
<script src="{{ url_for('static', filename='js/lib/common.js') }}"></script>
|
||||
@@ -98,6 +98,7 @@
|
||||
var flagContainer = "{{ model.FLAG_CONTAINER }}";
|
||||
var flagContainerInput = "{{ model.FLAG_CONTAINER_INPUT }}";
|
||||
var flagCounty = "{{ model.FLAG_COUNTY }}";
|
||||
var flagCsrfToken = "{{ model.FLAG_CSRF_TOKEN }}";
|
||||
var flagCurrency = "{{ model.FLAG_CURRENCY }}";
|
||||
var flagDelete = "{{ model.FLAG_DELETE }}";
|
||||
var flagDescription = "{{ model.FLAG_DESCRIPTION }}";
|
||||
@@ -233,7 +234,6 @@
|
||||
var idTableMain = "#{{ model.ID_TABLE_MAIN }}";
|
||||
var idTextareaConfirm = "#{{ model.ID_TEXTAREA_CONFIRM }}";
|
||||
var isUserLoggedIn = "{{ model.output_bool(model.IS_USER_LOGGED_IN) }}";
|
||||
var nameCSRFToken = "{{ model.NAME_CSRF_TOKEN }}";
|
||||
var _pathHost = "{{ model.get_url_host() }}";
|
||||
var _rowBlank = null;
|
||||
var titlePageCurrent = "{{ model.title }}";
|
||||
|
||||
Reference in New Issue
Block a user