Commit ba5481a0 authored by Your Name's avatar Your Name

Sexurity measures!

parent 5c8af90a
...@@ -178,6 +178,12 @@ Examples: ...@@ -178,6 +178,12 @@ Examples:
action='store_true', action='store_true',
help='Disable web dashboard (PyQt interface only)' help='Disable web dashboard (PyQt interface only)'
) )
parser.add_argument(
'--edit-odds',
action='store_true',
help='Enable manual odds editing from web interface/API (admin only, default: disabled for security)'
)
# Screen cast options # Screen cast options
...@@ -211,7 +217,7 @@ Examples: ...@@ -211,7 +217,7 @@ Examples:
parser.add_argument( parser.add_argument(
'--version', '--version',
action='version', action='version',
version='MbetterClient 1.0.16' version='MbetterClient 1.0.19'
) )
# Timer options # Timer options
...@@ -311,6 +317,7 @@ def main(): ...@@ -311,6 +317,7 @@ def main():
settings.enable_qt = not args.no_qt and not args.headless settings.enable_qt = not args.no_qt and not args.headless
settings.enable_headless = args.headless settings.enable_headless = args.headless
settings.enable_web = not args.no_web settings.enable_web = not args.no_web
settings.edit_odds = args.edit_odds
# Timer settings # Timer settings
if args.start_timer is not None: if args.start_timer is not None:
......
...@@ -4,7 +4,7 @@ MbetterClient - Cross-platform multimedia client application ...@@ -4,7 +4,7 @@ MbetterClient - Cross-platform multimedia client application
A multi-threaded application with video playback, web dashboard, and REST API integration. A multi-threaded application with video playback, web dashboard, and REST API integration.
""" """
__version__ = "1.0.17" __version__ = "1.0.19"
__author__ = "MBetter Project" __author__ = "MBetter Project"
__email__ = "dev@mbetter.net" __email__ = "dev@mbetter.net"
__description__ = "Cross-platform multimedia client with video overlay and web dashboard" __description__ = "Cross-platform multimedia client with video overlay and web dashboard"
......
...@@ -262,7 +262,7 @@ class ApiConfig: ...@@ -262,7 +262,7 @@ class ApiConfig:
# Request settings # Request settings
verify_ssl: bool = True verify_ssl: bool = True
user_agent: str = "MbetterClient/1.0r16" user_agent: str = "MbetterClient/1.0r19"
max_response_size_mb: int = 100 max_response_size_mb: int = 100
# Additional API client settings # Additional API client settings
...@@ -403,7 +403,7 @@ class AppSettings: ...@@ -403,7 +403,7 @@ class AppSettings:
timer: TimerConfig = field(default_factory=TimerConfig) timer: TimerConfig = field(default_factory=TimerConfig)
# Application settings # Application settings
version: str = "1.0.17" version: str = "1.0.19"
debug_mode: bool = False debug_mode: bool = False
dev_message: bool = False # Enable debug mode showing only message bus messages dev_message: bool = False # Enable debug mode showing only message bus messages
debug_messages: bool = False # Show all messages passing through the message bus on screen debug_messages: bool = False # Show all messages passing through the message bus on screen
...@@ -415,6 +415,7 @@ class AppSettings: ...@@ -415,6 +415,7 @@ class AppSettings:
enable_api_client: bool = True enable_api_client: bool = True
enable_screen_cast: bool = True # Enabled by default, can be disabled with --no-screen-cast enable_screen_cast: bool = True # Enabled by default, can be disabled with --no-screen-cast
enable_report_sync: bool = True # Enabled by default, can be disabled with --no-report-sync enable_report_sync: bool = True # Enabled by default, can be disabled with --no-report-sync
edit_odds: bool = False # Disabled by default for security, enable with --edit-odds for admin access only
# Runtime settings (not persisted) # Runtime settings (not persisted)
fullscreen: bool = True fullscreen: bool = True
......
...@@ -358,6 +358,7 @@ class WebDashboard(ThreadedComponent): ...@@ -358,6 +358,7 @@ class WebDashboard(ThreadedComponent):
api_bp.config_manager = self.config_manager api_bp.config_manager = self.config_manager
api_bp.message_bus = self.message_bus api_bp.message_bus = self.message_bus
api_bp.socketio = self.socketio api_bp.socketio = self.socketio
api_bp.settings = self.settings
# Pass dependencies to screen cast blueprint # Pass dependencies to screen cast blueprint
screen_cast_bp.message_bus = self.message_bus screen_cast_bp.message_bus = self.message_bus
......
...@@ -167,6 +167,7 @@ api_bp.auth_manager = None ...@@ -167,6 +167,7 @@ api_bp.auth_manager = None
api_bp.db_manager = None api_bp.db_manager = None
api_bp.config_manager = None api_bp.config_manager = None
api_bp.message_bus = None api_bp.message_bus = None
api_bp.settings = None
# HLS Streaming Routes (no authentication required) # HLS Streaming Routes (no authentication required)
...@@ -2665,6 +2666,23 @@ def system_status(): ...@@ -2665,6 +2666,23 @@ def system_status():
return jsonify({"error": str(e)}), 500 return jsonify({"error": str(e)}), 500
@api_bp.route('/settings')
@get_api_auth_decorator()
def get_app_settings():
"""Get application settings including edit_odds flag"""
try:
settings = getattr(api_bp, 'settings', None)
if not settings:
return jsonify({"error": "Settings not available"}), 500
return jsonify({
"edit_odds": getattr(settings, 'edit_odds', False)
})
except Exception as e:
logger.error(f"API settings error: {e}")
return jsonify({"error": str(e)}), 500
@api_bp.route('/debug/match-status') @api_bp.route('/debug/match-status')
@get_api_auth_decorator(require_admin=True) @get_api_auth_decorator(require_admin=True)
def debug_match_status(): def debug_match_status():
...@@ -4600,6 +4618,26 @@ def get_matches_template_details(template_id): ...@@ -4600,6 +4618,26 @@ def get_matches_template_details(template_id):
@get_api_auth_decorator() @get_api_auth_decorator()
def update_matches_template_odds(template_id): def update_matches_template_odds(template_id):
"""Update odds for a match template""" """Update odds for a match template"""
# Check if edit_odds is enabled (disabled by default for security)
# Only allow if explicitly enabled via command line --edit-odds flag
settings = getattr(api_bp, 'settings', None)
edit_odds_enabled = getattr(settings, 'edit_odds', False) if settings else False
# Check if user is admin (required for editing odds)
from flask import request
is_admin = False
if hasattr(request, 'current_user') and request.current_user:
is_admin = request.current_user.get('is_admin', False)
if not edit_odds_enabled:
return jsonify({
"error": "Manual odds editing is disabled. Start with --edit-odds flag to enable admin-only odds editing.",
"edit_odds_enabled": False
}), 403
if not is_admin:
return jsonify({"error": "Admin access required to modify odds"}), 403
try: try:
from ..database.models import MatchTemplateModel, MatchOutcomeTemplateModel from ..database.models import MatchTemplateModel, MatchOutcomeTemplateModel
...@@ -7903,13 +7941,11 @@ def get_match_reports(): ...@@ -7903,13 +7941,11 @@ def get_match_reports():
match_stats[match_id]['bets_count'] += 1 match_stats[match_id]['bets_count'] += 1
match_stats[match_id]['payin'] += float(detail.amount) match_stats[match_id]['payin'] += float(detail.amount)
# Calculate potential payout if bet was won (use same logic as bet list) # Calculate payout using actual win_amount (stored when bet was settled)
match = session.query(MatchModel).filter_by(id=match_id).first() # This ensures consistency with bet list and avoids recalculation issues
if is_bet_detail_winning(detail, match, session): if is_bet_detail_winning(detail, match, session):
if match: # Use the actual win_amount stored when the bet was settled
outcomes_dict = match.get_outcomes_dict() match_stats[match_id]['payout'] += float(detail.win_amount or 0)
odds = outcomes_dict.get(detail.outcome, 0.0)
match_stats[match_id]['payout'] += float(detail.amount) * float(odds)
# Get match information and merge with stats # Get match information and merge with stats
matches_data = [] matches_data = []
......
...@@ -106,7 +106,7 @@ ...@@ -106,7 +106,7 @@
</div> </div>
<!-- Edit Odds Card --> <!-- Edit Odds Card -->
<div class="row"> <div class="row" id="edit-odds-section">
<div class="col-12"> <div class="col-12">
<div class="card mb-4"> <div class="card mb-4">
<div class="card-header d-flex justify-content-between align-items-center"> <div class="card-header d-flex justify-content-between align-items-center">
...@@ -162,10 +162,35 @@ const templateId = config.templateId; ...@@ -162,10 +162,35 @@ const templateId = config.templateId;
let cachedTemplateData = null; let cachedTemplateData = null;
let isInitialLoad = true; let isInitialLoad = true;
let editOddsEnabled = false;
// Load template details on page load // Load template details on page load
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
loadTemplateDetails(); // First, check if edit_odds is enabled
fetch('/api/settings')
.then(response => response.json())
.then(settings => {
editOddsEnabled = settings.edit_odds || false;
console.log('Edit odds enabled:', editOddsEnabled);
// Hide edit odds form if disabled
const editOddsSection = document.getElementById('edit-odds-section');
if (!editOddsEnabled && editOddsSection) {
editOddsSection.style.display = 'none';
}
})
.catch(err => {
console.error('Error loading settings:', err);
// Hide edit odds form by default if we can't check
const editOddsSection = document.getElementById('edit-odds-section');
if (editOddsSection) {
editOddsSection.style.display = 'none';
}
})
.finally(() => {
// Then load template details
loadTemplateDetails();
});
}); });
function loadTemplateDetails() { function loadTemplateDetails() {
...@@ -299,6 +324,12 @@ function renderOutcomesTable(outcomes) { ...@@ -299,6 +324,12 @@ function renderOutcomesTable(outcomes) {
} }
function saveOdds() { function saveOdds() {
// Check if edit is enabled
if (!editOddsEnabled) {
showError('Manual odds editing is disabled. Start the application with --edit-odds flag to enable it.');
return;
}
const saveBtn = document.getElementById('save-odds-btn'); const saveBtn = document.getElementById('save-odds-btn');
const tbody = document.getElementById('outcomes-tbody'); const tbody = document.getElementById('outcomes-tbody');
const rows = tbody.querySelectorAll('tr'); const rows = tbody.querySelectorAll('tr');
......
# MbetterClient v1.0.16
Cross-platform multimedia client application
## Installation
1. Extract this package to your desired location
2. Run the executable file
3. The application will create necessary configuration files on first run
## System Requirements
- **Operating System**: Linux 6.12.15-amd64
- **Architecture**: x86_64
- **Memory**: 512 MB RAM minimum, 1 GB recommended
- **Disk Space**: 100 MB free space
## Configuration
The application stores its configuration and database in:
- **Windows**: `%APPDATA%\MbetterClient`
- **macOS**: `~/Library/Application Support/MbetterClient`
- **Linux**: `~/.config/MbetterClient`
## Web Interface
By default, the web interface is available at: http://localhost:5001
Default login credentials:
- Username: admin
- Password: admin
**Please change the default password after first login.**
## Support
For support and documentation, please visit: https://git.nexlab.net/mbetter/mbetterc
## Version Information
- Version: 1.0.16
- Build Date: sissy
- Platform: Linux-6.12.15-amd64-x86_64-with-glibc2.42
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment