Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
M
MBetterc
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Mbetter
MBetterc
Commits
40789eb5
Commit
40789eb5
authored
Dec 01, 2025
by
Stefy Lanza (nextime / spora )
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fixed web auth
parent
ca38e0be
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
120 additions
and
48 deletions
+120
-48
auth.py
mbetterclient/web_dashboard/auth.py
+74
-46
routes.py
mbetterclient/web_dashboard/routes.py
+46
-2
No files found.
mbetterclient/web_dashboard/auth.py
View file @
40789eb5
...
@@ -471,68 +471,96 @@ class AuthManager:
...
@@ -471,68 +471,96 @@ class AuthManager:
"""Hash token for secure storage"""
"""Hash token for secure storage"""
return
hashlib
.
sha256
(
token
.
encode
())
.
hexdigest
()
return
hashlib
.
sha256
(
token
.
encode
())
.
hexdigest
()
def
require_auth
(
self
,
f
):
def
require_auth
(
self
,
f
=
None
):
"""Decorator for routes requiring authentication"""
"""Decorator for routes requiring authentication"""
from
functools
import
wraps
from
functools
import
wraps
@
wraps
(
f
)
def
decorator
(
func
):
def
decorated_function
(
*
args
,
**
kwargs
):
@
wraps
(
func
)
auth_header
=
request
.
headers
.
get
(
'Authorization'
)
def
decorated_function
(
*
args
,
**
kwargs
):
auth_header
=
request
.
headers
.
get
(
'Authorization'
)
if
auth_header
and
auth_header
.
startswith
(
'Bearer '
):
token
=
auth_header
.
split
(
' '
,
1
)[
1
]
if
auth_header
and
auth_header
.
startswith
(
'Bearer '
):
token
=
auth_header
.
split
(
' '
,
1
)[
1
]
# Try JWT token first
payload
=
self
.
verify_jwt_token
(
token
)
# Try JWT token first
if
payload
:
payload
=
self
.
verify_jwt_token
(
token
)
request
.
current_user
=
payload
if
payload
:
return
f
(
*
args
,
**
kwargs
)
request
.
current_user
=
payload
return
func
(
*
args
,
**
kwargs
)
# Try API token
api_data
=
self
.
verify_api_token
(
token
)
# Try API token
if
api_data
:
api_data
=
self
.
verify_api_token
(
token
)
request
.
current_user
=
api_data
if
api_data
:
return
f
(
*
args
,
**
kwargs
)
request
.
current_user
=
api_data
return
func
(
*
args
,
**
kwargs
)
return
{
'error'
:
'Authentication required'
},
401
return
{
'error'
:
'Authentication required'
},
401
return
decorated_function
return
decorated_function
# If called without arguments, return the decorator
if
f
is
None
:
return
decorator
# If called with a function, apply the decorator immediately
else
:
return
decorator
(
f
)
def
require_admin
(
self
,
f
):
def
require_admin
(
self
,
f
=
None
):
"""Decorator for routes requiring admin access"""
"""Decorator for routes requiring admin access"""
from
functools
import
wraps
from
functools
import
wraps
@
wraps
(
f
)
def
decorator
(
func
):
def
decorated_function
(
*
args
,
**
kwargs
):
@
wraps
(
func
)
if
not
hasattr
(
request
,
'current_user'
):
def
decorated_function
(
*
args
,
**
kwargs
):
return
{
'error'
:
'Authentication required'
},
401
if
not
hasattr
(
request
,
'current_user'
):
return
{
'error'
:
'Authentication required'
},
401
user_role
=
request
.
current_user
.
get
(
'role'
,
'normal'
)
is_admin
=
request
.
current_user
.
get
(
'is_admin'
,
False
)
user_role
=
request
.
current_user
.
get
(
'role'
,
'normal'
)
is_admin
=
request
.
current_user
.
get
(
'is_admin'
,
False
)
if
user_role
!=
'admin'
and
not
is_admin
:
return
{
'error'
:
'Admin access required'
},
403
if
user_role
!=
'admin'
and
not
is_admin
:
return
{
'error'
:
'Admin access required'
},
403
return
f
(
*
args
,
**
kwargs
)
return
func
(
*
args
,
**
kwargs
)
return
decorated_function
return
decorated_function
# If called without arguments, return the decorator
if
f
is
None
:
return
decorator
# If called with a function, apply the decorator immediately
else
:
return
decorator
(
f
)
def
require_role
(
self
,
allowed_roles
:
List
[
str
]):
def
require_role
(
self
,
allowed_roles
:
List
[
str
]):
"""Decorator for routes requiring specific roles"""
"""Decorator for routes requiring specific roles"""
from
functools
import
wraps
from
functools
import
wraps
def
decorator
(
f
):
def
decorator
(
f
):
@
wraps
(
f
)
@
wraps
(
f
)
def
decorated_function
(
*
args
,
**
kwargs
):
def
decorated_function
(
*
args
,
**
kwargs
):
if
not
hasattr
(
request
,
'current_user'
):
if
not
hasattr
(
request
,
'current_user'
):
return
{
'error'
:
'Authentication required'
},
401
return
{
'error'
:
'Authentication required'
},
401
user_role
=
request
.
current_user
.
get
(
'role'
,
'normal'
)
user_role
=
request
.
current_user
.
get
(
'role'
,
'normal'
)
if
user_role
not
in
allowed_roles
:
if
user_role
not
in
allowed_roles
:
return
{
'error'
:
f
'Access denied. Required roles: {", ".join(allowed_roles)}'
},
403
return
{
'error'
:
f
'Access denied. Required roles: {", ".join(allowed_roles)}'
},
403
return
f
(
*
args
,
**
kwargs
)
return
f
(
*
args
,
**
kwargs
)
return
decorated_function
return
decorated_function
return
decorator
return
decorator
\ No newline at end of file
def
get_auth_decorator
(
self
,
require_admin
=
False
):
"""Get the appropriate auth decorator based on availability"""
if
hasattr
(
self
,
'_app'
)
and
self
.
_app
:
if
require_admin
:
return
self
.
require_admin
()
else
:
return
self
.
require_auth
()
else
:
# Fallback to Flask-Login's login_required
from
flask_login
import
login_required
return
login_required
\ No newline at end of file
mbetterclient/web_dashboard/routes.py
View file @
40789eb5
...
@@ -15,6 +15,16 @@ from werkzeug.utils import secure_filename
...
@@ -15,6 +15,16 @@ from werkzeug.utils import secure_filename
from
.auth
import
AuthenticatedUser
from
.auth
import
AuthenticatedUser
from
..core.message_bus
import
Message
,
MessageType
from
..core.message_bus
import
Message
,
MessageType
def
conditional_auth_decorator
(
condition
,
auth_decorator
,
fallback_decorator
=
login_required
):
"""Helper function for conditional auth decorators"""
def
decorator
(
func
):
if
condition
:
return
auth_decorator
(
func
)
else
:
return
fallback_decorator
(
func
)
return
decorator
logger
=
logging
.
getLogger
(
__name__
)
logger
=
logging
.
getLogger
(
__name__
)
# Blueprint definitions
# Blueprint definitions
...
@@ -2059,8 +2069,25 @@ def get_cashier_pending_matches():
...
@@ -2059,8 +2069,25 @@ def get_cashier_pending_matches():
# Allow access from localhost without authentication
# Allow access from localhost without authentication
if
request
.
remote_addr
==
'127.0.0.1'
:
if
request
.
remote_addr
==
'127.0.0.1'
:
pass
# Skip authentication
pass
# Skip authentication
# Check if user is authenticated via Flask-Login (web interface)
elif
current_user
.
is_authenticated
:
pass
# User is logged in via web interface
elif
hasattr
(
api_bp
,
'auth_manager'
)
and
api_bp
.
auth_manager
:
elif
hasattr
(
api_bp
,
'auth_manager'
)
and
api_bp
.
auth_manager
:
api_bp
.
auth_manager
.
require_auth
()
# Apply API token authentication manually
auth_header
=
request
.
headers
.
get
(
'Authorization'
)
if
auth_header
and
auth_header
.
startswith
(
'Bearer '
):
token
=
auth_header
.
split
(
' '
,
1
)[
1
]
payload
=
api_bp
.
auth_manager
.
verify_jwt_token
(
token
)
if
payload
:
request
.
current_user
=
payload
else
:
api_data
=
api_bp
.
auth_manager
.
verify_api_token
(
token
)
if
api_data
:
request
.
current_user
=
api_data
else
:
return
{
'error'
:
'Authentication required'
},
401
else
:
return
{
'error'
:
'Authentication required'
},
401
from
..database.models
import
MatchModel
from
..database.models
import
MatchModel
from
datetime
import
datetime
,
date
,
timedelta
from
datetime
import
datetime
,
date
,
timedelta
...
@@ -2213,8 +2240,25 @@ def get_fixture_details(fixture_id):
...
@@ -2213,8 +2240,25 @@ def get_fixture_details(fixture_id):
# Allow access from localhost without authentication
# Allow access from localhost without authentication
if
request
.
remote_addr
==
'127.0.0.1'
:
if
request
.
remote_addr
==
'127.0.0.1'
:
pass
# Skip authentication
pass
# Skip authentication
# Check if user is authenticated via Flask-Login (web interface)
elif
current_user
.
is_authenticated
:
pass
# User is logged in via web interface
elif
hasattr
(
api_bp
,
'auth_manager'
)
and
api_bp
.
auth_manager
:
elif
hasattr
(
api_bp
,
'auth_manager'
)
and
api_bp
.
auth_manager
:
api_bp
.
auth_manager
.
require_auth
()
# Apply auth check manually for conditional auth
auth_header
=
request
.
headers
.
get
(
'Authorization'
)
if
auth_header
and
auth_header
.
startswith
(
'Bearer '
):
token
=
auth_header
.
split
(
' '
,
1
)[
1
]
payload
=
api_bp
.
auth_manager
.
verify_jwt_token
(
token
)
if
payload
:
request
.
current_user
=
payload
else
:
api_data
=
api_bp
.
auth_manager
.
verify_api_token
(
token
)
if
api_data
:
request
.
current_user
=
api_data
else
:
return
{
'error'
:
'Authentication required'
},
401
else
:
return
{
'error'
:
'Authentication required'
},
401
from
..database.models
import
MatchModel
,
MatchOutcomeModel
from
..database.models
import
MatchModel
,
MatchOutcomeModel
from
datetime
import
datetime
,
date
from
datetime
import
datetime
,
date
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment