Implement proper CORS configuration for secure cross-origin usage
- Add flask-cors dependency and configure CORS with security best practices - Support configurable CORS origins via environment variables - Separate admin endpoint CORS configuration for enhanced security - Create comprehensive CORS configuration documentation - Add apiClient utility for CORS-aware frontend requests - Include CORS test page for validation - Update README with CORS configuration instructions 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
228
test-cors.html
Normal file
228
test-cors.html
Normal file
@@ -0,0 +1,228 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>CORS Test for Talk2Me</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
max-width: 800px;
|
||||
margin: 50px auto;
|
||||
padding: 20px;
|
||||
}
|
||||
.test-result {
|
||||
margin: 10px 0;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.success {
|
||||
background-color: #d4edda;
|
||||
color: #155724;
|
||||
border: 1px solid #c3e6cb;
|
||||
}
|
||||
.error {
|
||||
background-color: #f8d7da;
|
||||
color: #721c24;
|
||||
border: 1px solid #f5c6cb;
|
||||
}
|
||||
button {
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
padding: 10px 20px;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
margin: 5px;
|
||||
}
|
||||
button:hover {
|
||||
background-color: #0056b3;
|
||||
}
|
||||
input {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
margin: 10px 0;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 5px;
|
||||
}
|
||||
#results {
|
||||
margin-top: 20px;
|
||||
}
|
||||
pre {
|
||||
background-color: #f8f9fa;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
overflow-x: auto;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>CORS Test for Talk2Me API</h1>
|
||||
|
||||
<p>This page tests CORS configuration for the Talk2Me API. Open this file from a different origin (e.g., file:// or a different port) to test cross-origin requests.</p>
|
||||
|
||||
<div>
|
||||
<label for="apiUrl">API Base URL:</label>
|
||||
<input type="text" id="apiUrl" placeholder="http://localhost:5005" value="http://localhost:5005">
|
||||
</div>
|
||||
|
||||
<h2>Tests:</h2>
|
||||
|
||||
<button onclick="testHealthEndpoint()">Test Health Endpoint</button>
|
||||
<button onclick="testPreflightRequest()">Test Preflight Request</button>
|
||||
<button onclick="testTranscribeEndpoint()">Test Transcribe Endpoint (OPTIONS)</button>
|
||||
<button onclick="testWithCredentials()">Test With Credentials</button>
|
||||
|
||||
<div id="results"></div>
|
||||
|
||||
<script>
|
||||
function addResult(test, success, message, details = null) {
|
||||
const resultsDiv = document.getElementById('results');
|
||||
const resultDiv = document.createElement('div');
|
||||
resultDiv.className = `test-result ${success ? 'success' : 'error'}`;
|
||||
|
||||
let html = `<strong>${test}:</strong> ${message}`;
|
||||
if (details) {
|
||||
html += `<pre>${JSON.stringify(details, null, 2)}</pre>`;
|
||||
}
|
||||
resultDiv.innerHTML = html;
|
||||
resultsDiv.appendChild(resultDiv);
|
||||
}
|
||||
|
||||
function getApiUrl() {
|
||||
return document.getElementById('apiUrl').value.trim();
|
||||
}
|
||||
|
||||
async function testHealthEndpoint() {
|
||||
const apiUrl = getApiUrl();
|
||||
try {
|
||||
const response = await fetch(`${apiUrl}/health`, {
|
||||
method: 'GET',
|
||||
mode: 'cors',
|
||||
headers: {
|
||||
'Origin': window.location.origin
|
||||
}
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
// Check CORS headers
|
||||
const corsHeaders = {
|
||||
'Access-Control-Allow-Origin': response.headers.get('Access-Control-Allow-Origin'),
|
||||
'Access-Control-Allow-Credentials': response.headers.get('Access-Control-Allow-Credentials')
|
||||
};
|
||||
|
||||
addResult('Health Endpoint GET', true, 'Request successful', {
|
||||
status: response.status,
|
||||
data: data,
|
||||
corsHeaders: corsHeaders
|
||||
});
|
||||
} catch (error) {
|
||||
addResult('Health Endpoint GET', false, error.message);
|
||||
}
|
||||
}
|
||||
|
||||
async function testPreflightRequest() {
|
||||
const apiUrl = getApiUrl();
|
||||
try {
|
||||
const response = await fetch(`${apiUrl}/api/push-public-key`, {
|
||||
method: 'OPTIONS',
|
||||
mode: 'cors',
|
||||
headers: {
|
||||
'Origin': window.location.origin,
|
||||
'Access-Control-Request-Method': 'GET',
|
||||
'Access-Control-Request-Headers': 'content-type'
|
||||
}
|
||||
});
|
||||
|
||||
const corsHeaders = {
|
||||
'Access-Control-Allow-Origin': response.headers.get('Access-Control-Allow-Origin'),
|
||||
'Access-Control-Allow-Methods': response.headers.get('Access-Control-Allow-Methods'),
|
||||
'Access-Control-Allow-Headers': response.headers.get('Access-Control-Allow-Headers'),
|
||||
'Access-Control-Max-Age': response.headers.get('Access-Control-Max-Age')
|
||||
};
|
||||
|
||||
addResult('Preflight Request', response.ok, `Status: ${response.status}`, corsHeaders);
|
||||
} catch (error) {
|
||||
addResult('Preflight Request', false, error.message);
|
||||
}
|
||||
}
|
||||
|
||||
async function testTranscribeEndpoint() {
|
||||
const apiUrl = getApiUrl();
|
||||
try {
|
||||
const response = await fetch(`${apiUrl}/transcribe`, {
|
||||
method: 'OPTIONS',
|
||||
mode: 'cors',
|
||||
headers: {
|
||||
'Origin': window.location.origin,
|
||||
'Access-Control-Request-Method': 'POST',
|
||||
'Access-Control-Request-Headers': 'content-type'
|
||||
}
|
||||
});
|
||||
|
||||
const corsHeaders = {
|
||||
'Access-Control-Allow-Origin': response.headers.get('Access-Control-Allow-Origin'),
|
||||
'Access-Control-Allow-Methods': response.headers.get('Access-Control-Allow-Methods'),
|
||||
'Access-Control-Allow-Headers': response.headers.get('Access-Control-Allow-Headers'),
|
||||
'Access-Control-Allow-Credentials': response.headers.get('Access-Control-Allow-Credentials')
|
||||
};
|
||||
|
||||
addResult('Transcribe Endpoint OPTIONS', response.ok, `Status: ${response.status}`, corsHeaders);
|
||||
} catch (error) {
|
||||
addResult('Transcribe Endpoint OPTIONS', false, error.message);
|
||||
}
|
||||
}
|
||||
|
||||
async function testWithCredentials() {
|
||||
const apiUrl = getApiUrl();
|
||||
try {
|
||||
const response = await fetch(`${apiUrl}/health`, {
|
||||
method: 'GET',
|
||||
mode: 'cors',
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Origin': window.location.origin
|
||||
}
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
addResult('Request with Credentials', true, 'Request successful', {
|
||||
status: response.status,
|
||||
credentialsIncluded: true,
|
||||
data: data
|
||||
});
|
||||
} catch (error) {
|
||||
addResult('Request with Credentials', false, error.message);
|
||||
}
|
||||
}
|
||||
|
||||
// Clear results before running new tests
|
||||
function clearResults() {
|
||||
document.getElementById('results').innerHTML = '';
|
||||
}
|
||||
|
||||
// Add event listeners
|
||||
document.querySelectorAll('button').forEach(button => {
|
||||
button.addEventListener('click', (e) => {
|
||||
if (!e.target.textContent.includes('Test')) return;
|
||||
clearResults();
|
||||
});
|
||||
});
|
||||
|
||||
// Show current origin
|
||||
window.addEventListener('load', () => {
|
||||
const info = document.createElement('div');
|
||||
info.style.marginBottom = '20px';
|
||||
info.style.padding = '10px';
|
||||
info.style.backgroundColor = '#e9ecef';
|
||||
info.style.borderRadius = '5px';
|
||||
info.innerHTML = `<strong>Current Origin:</strong> ${window.location.origin}<br>
|
||||
<strong>Protocol:</strong> ${window.location.protocol}<br>
|
||||
<strong>Note:</strong> For effective CORS testing, open this file from a different origin than your API server.`;
|
||||
document.body.insertBefore(info, document.querySelector('h2'));
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Reference in New Issue
Block a user