# Secure: Safe string formatting in Flask
from flask import Flask, request, jsonify, render_template_string
import datetime
import re
from markupsafe import escape
app = Flask(__name__)
# Safe: Input validation and template system
@app.route('/greet')
def safe_greet_user():
name = request.args.get('name', '')
template_type = request.args.get('template', 'default')
try:
# Validate inputs
validated_name = validate_user_name(name)
validated_template = validate_template_type(template_type)
# Safe: Use predefined templates
message = generate_safe_greeting(validated_name, validated_template)
return message
except ValueError as e:
return jsonify({'error': str(e)}), 400
def validate_user_name(name):
if not name:
raise ValueError('Name is required')
if len(name) > 50:
raise ValueError('Name too long')
# Only allow safe characters
if not re.match(r'^[a-zA-Z\s.-]+$', name):
raise ValueError('Name contains invalid characters')
return escape(name)
def validate_template_type(template_type):
allowed_templates = ['default', 'formal', 'casual', 'business']
if template_type not in allowed_templates:
raise ValueError('Invalid template type')
return template_type
def generate_safe_greeting(name, template_type):
# Safe: Predefined templates
templates = {
'default': 'Hello, {name}!',
'formal': 'Good day, {name}.',
'casual': 'Hey {name}!',
'business': 'Dear {name},'
}
template = templates[template_type]
# Safe: Use .format() with validated input
return template.format(name=name)
# Safe: Data formatting with validation
@app.route('/format_data')
def safe_format_data():
data = request.args.get('data', '')
format_type = request.args.get('format', 'string')
try:
# Validate inputs
validated_data = validate_format_data(data)
validated_format = validate_format_type(format_type)
# Format data safely
result = format_data_safely(validated_data, validated_format)
return jsonify({'result': result})
except ValueError as e:
return jsonify({'error': str(e)}), 400
def validate_format_data(data):
if len(data) > 1000:
raise ValueError('Data too long')
return escape(data)
def validate_format_type(format_type):
allowed_formats = ['string', 'upper', 'lower', 'title', 'truncate']
if format_type not in allowed_formats:
raise ValueError('Invalid format type')
return format_type
def format_data_safely(data, format_type):
# Safe: Predefined formatting operations
formatters = {
'string': lambda x: str(x),
'upper': lambda x: str(x).upper(),
'lower': lambda x: str(x).lower(),
'title': lambda x: str(x).title(),
'truncate': lambda x: str(x)[:100] + '...' if len(str(x)) > 100 else str(x)
}
return formatters[format_type](data)
# Safe: Structured logging
@app.route('/log')
def safe_log_message():
log_level = request.args.get('level', 'info')
message = request.args.get('message', '')
context = request.args.get('context', '')
try:
# Validate inputs
validated_log = validate_log_request(log_level, message, context)
# Log safely
log_message_safely(validated_log)
return jsonify({'status': 'Message logged successfully'})
except ValueError as e:
return jsonify({'error': str(e)}), 400
def validate_log_request(level, message, context):
# Validate log level
allowed_levels = ['debug', 'info', 'warning', 'error']
if level not in allowed_levels:
raise ValueError('Invalid log level')
# Validate message
if not message or len(message) > 500:
raise ValueError('Invalid message length')
# Sanitize inputs
clean_message = re.sub(r'[\x00-\x1f\x7f-\x9f]', '', message)
clean_context = re.sub(r'[\x00-\x1f\x7f-\x9f]', '', context) if context else ''
return {
'level': level,
'message': clean_message,
'context': clean_context
}
def log_message_safely(log_data):
# Safe: Structured logging with validated data
log_entry = {
'timestamp': datetime.datetime.utcnow().isoformat(),
'level': log_data['level'],
'message': log_data['message'],
'context': log_data['context']
}
# Use appropriate logging level
if log_data['level'] == 'debug':
app.logger.debug('User log: %(message)s [%(context)s]', log_entry)
elif log_data['level'] == 'info':
app.logger.info('User log: %(message)s [%(context)s]', log_entry)
elif log_data['level'] == 'warning':
app.logger.warning('User log: %(message)s [%(context)s]', log_entry)
elif log_data['level'] == 'error':
app.logger.error('User log: %(message)s [%(context)s]', log_entry)
# Safe: Report generation with templates
@app.route('/report')
def safe_generate_report():
report_type = request.form.get('type', '')
report_data = {
'user': request.form.get('user', ''),
'start_date': request.form.get('start_date', ''),
'end_date': request.form.get('end_date', '')
}
try:
# Validate inputs
validated_report = validate_report_request(report_type, report_data)
# Generate report safely
report = generate_report_safely(validated_report)
return report
except ValueError as e:
return jsonify({'error': str(e)}), 400
def validate_report_request(report_type, data):
# Validate report type
allowed_types = ['user_activity', 'system_status', 'error_summary']
if report_type not in allowed_types:
raise ValueError('Invalid report type')
# Validate user
user = data.get('user', '')
if user and not re.match(r'^[a-zA-Z0-9_.-]+$', user):
raise ValueError('Invalid user format')
# Validate dates
start_date = data.get('start_date', '')
end_date = data.get('end_date', '')
if start_date:
try:
datetime.datetime.strptime(start_date, '%Y-%m-%d')
except ValueError:
raise ValueError('Invalid start date format')
if end_date:
try:
datetime.datetime.strptime(end_date, '%Y-%m-%d')
except ValueError:
raise ValueError('Invalid end date format')
return {
'type': report_type,
'user': escape(user) if user else '',
'start_date': start_date,
'end_date': end_date
}
def generate_report_safely(report_data):
# Safe: Use Flask templates
if report_data['type'] == 'user_activity':
template = '''
User Activity Report
User: {{ user }}
Period: {{ start_date }} to {{ end_date }}
Generated: {{ timestamp }}
'''
elif report_data['type'] == 'system_status':
template = '''
System Status Report
Period: {{ start_date }} to {{ end_date }}
Generated: {{ timestamp }}
Status: Operational
'''
elif report_data['type'] == 'error_summary':
template = '''
Error Summary Report
Period: {{ start_date }} to {{ end_date }}
Generated: {{ timestamp }}
Total Errors: 0
'''
# Safe: Use render_template_string with validated data
return render_template_string(template,
user=report_data['user'],
start_date=report_data['start_date'],
end_date=report_data['end_date'],
timestamp=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
)
# Safe: Error handling without format strings
@app.route('/error')
def safe_show_error():
error_code = request.args.get('code', '')
try:
# Validate error code
validated_code = validate_error_code(error_code)
# Get safe error message
error_info = get_safe_error_info(validated_code)
return jsonify(error_info)
except ValueError as e:
return jsonify({'error': 'Invalid error code'}), 400
def validate_error_code(code):
if not code or not code.isdigit():
raise ValueError('Invalid error code format')
code_int = int(code)
if code_int < 100 or code_int > 999:
raise ValueError('Error code out of range')
return code_int
def get_safe_error_info(error_code):
# Safe: Predefined error messages
error_messages = {
400: {'message': 'Bad Request', 'description': 'The request was invalid'},
401: {'message': 'Unauthorized', 'description': 'Authentication required'},
403: {'message': 'Forbidden', 'description': 'Access denied'},
404: {'message': 'Not Found', 'description': 'Resource not found'},
500: {'message': 'Internal Server Error', 'description': 'Server error occurred'}
}
return error_messages.get(error_code, {
'message': 'Unknown Error',
'description': 'An unknown error occurred'
})
# Safe: API response with structured data
@app.route('/api/format')
def safe_format_api_response():
response_type = request.json.get('type', '') if request.json else ''
data = request.json.get('data', {}) if request.json else {}
try:
# Validate inputs
validated_request = validate_api_format_request(response_type, data)
# Format response safely
response = format_api_response_safely(validated_request)
return jsonify(response)
except ValueError as e:
return jsonify({'error': str(e)}), 400
def validate_api_format_request(response_type, data):
# Validate response type
allowed_types = ['summary', 'detailed', 'minimal']
if response_type not in allowed_types:
raise ValueError('Invalid response type')
# Validate data structure
if not isinstance(data, dict):
raise ValueError('Data must be a dictionary')
# Sanitize data values
sanitized_data = {}
for key, value in data.items():
if isinstance(value, str) and len(value) <= 100:
sanitized_data[key] = escape(value)
elif isinstance(value, (int, float, bool)):
sanitized_data[key] = value
return {
'type': response_type,
'data': sanitized_data
}
def format_api_response_safely(request_data):
response_type = request_data['type']
data = request_data['data']
# Safe: Structured response based on type
if response_type == 'summary':
return {
'type': 'summary',
'count': len(data),
'keys': list(data.keys())
}
elif response_type == 'detailed':
return {
'type': 'detailed',
'data': data,
'metadata': {
'timestamp': datetime.datetime.utcnow().isoformat(),
'version': '1.0'
}
}
elif response_type == 'minimal':
return {
'type': 'minimal',
'status': 'ok'
}
if __name__ == '__main__':
app.run(debug=False)