Skip to content

Commit

Permalink
0.5.41 - frontend improvements, started implementing symlink library …
Browse files Browse the repository at this point in the history
…management page (not yet on frontend), CORS fixes
  • Loading branch information
godver3 committed Jan 14, 2025
1 parent 3542b2c commit 3acd62f
Show file tree
Hide file tree
Showing 22 changed files with 3,202 additions and 1,791 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -139,4 +139,5 @@ nohup.out
run.sh

~
config/config.json.backup
config/config.json.backup
config/secret_key
206 changes: 172 additions & 34 deletions cors_test.html
Original file line number Diff line number Diff line change
Expand Up @@ -75,48 +75,103 @@ <h1>CORS Test Page</h1>
</div>
<p class="debug-info">Testing against server: <span id="serverUrl"></span></p>
<div class="cookie-info">
<strong>Current Cookies:</strong>
<pre id="cookieInfo">None</pre>
<strong>Cookie Status:</strong>
<pre id="cookieInfo">Checking...</pre>
<div class="note" style="margin-top: 10px; font-size: 0.9em; color: #666;">
Note: Due to browser security, JavaScript might not be able to see the cookies directly,
but they are still being sent with requests. Check the server logs to confirm.
</div>
</div>

<button onclick="checkLoginStatus()">1. Check Login Status</button>
<button onclick="testTaskTimings()">2. Test Task Timings Access</button>
<button onclick="testTaskTimingsAPI()">3. Test Task Timings API</button>
<button onclick="checkServerCookies()">4. Check Server-Side Cookies</button>
<button onclick="testPreflightRequest()">5. Test Preflight Request</button>
<button onclick="testPostRequest()">6. Test POST Request</button>

<div id="status" class="status"></div>
<pre id="response"></pre>
</div>

<script>
// Get the target server URL from the current location
const targetServer = window.location.hostname === 'localhost'
? 'http://localhost:5000'
: `${window.location.protocol}//${window.location.hostname.replace('cors-test', 'cli-debrid')}`;

function getTargetServer() {
const hostname = window.location.hostname;
const protocol = window.location.protocol;

// Handle localhost
if (hostname === 'localhost' || hostname.match(/^(\d{1,3}\.){3}\d{1,3}$/)) {
return 'http://localhost:5000';
}

// For all other cases, replace the first subdomain with 'cli-debrid'
const parts = hostname.split('.');
if (parts.length > 2) {
parts[0] = 'cli-debrid';
} else {
parts.unshift('cli-debrid');
}
return `${protocol}//${parts.join('.')}`;
}

const targetServer = getTargetServer();
document.getElementById('serverUrl').textContent = targetServer;
document.getElementById('loginLink').href = `${targetServer}/auth/login`;
document.getElementById('loginLink').textContent = `${targetServer}/auth/login`;

// Set document.domain to allow cross-subdomain communication
try {
const domainParts = window.location.hostname.split('.');
if (domainParts.length > 2) {
document.domain = domainParts.slice(-2).join('.');
}
} catch (e) {
console.warn('Could not set document.domain:', e);
}

function updateCookieInfo() {
const cookieInfo = document.getElementById('cookieInfo');
const cookies = document.cookie;

// Try to parse and display individual cookies
let info = '';
info += 'Client-Side Cookie Info:\n';
if (cookies) {
const cookieList = cookies.split(';').map(cookie => cookie.trim());
cookieInfo.textContent = 'Cookies found:\n' + cookieList.join('\n');
const cookieList = cookies.split(';').map(cookie => {
const [name, value] = cookie.trim().split('=');
return `${name} = ${value.substring(0, 20)}${value.length > 20 ? '...' : ''}`;
});
info += cookieList.join('\n');
} else {
cookieInfo.textContent = 'No cookies present';
info += 'No cookies visible to JavaScript\n';
info += '(This is normal due to security settings)\n';
}

info += '\nDebug Info:\n';
info += `Location hostname: ${window.location.hostname}\n`;
info += `Target server: ${targetServer}\n`;
info += `Protocol: ${window.location.protocol}\n`;
info += `Port: ${window.location.port}\n`;
info += '\nNote: Cookies may still be sent with requests even if not visible here.\n';
info += 'Check server logs or network tab for confirmation.';

cookieInfo.innerHTML = info;
}

async function checkServerCookies() {
try {
showStatus('Checking server-side cookies...');
const response = await fetch(`${window.location.origin}/cookie-check`, {
method: 'GET',
credentials: 'include',
headers: {
'Accept': 'application/json',
'X-Requested-With': 'XMLHttpRequest'
}
});

const data = await response.text();
showResponse({
status: response.status,
statusText: response.statusText,
headers: Object.fromEntries([...response.headers.entries()]),
cookies: data
});

showStatus('Successfully checked server-side cookies');
} catch (error) {
showStatus('Error checking server-side cookies: ' + error.message, true);
console.error('Error:', error);
}
}

Expand All @@ -142,35 +197,50 @@ <h1>CORS Test Page</h1>

async function checkLoginStatus() {
try {
showStatus('Checking login status...');
const response = await fetch(`${targetServer}/auth/login`, {
method: 'GET',
credentials: 'include',
headers: {
'Accept': 'text/html',
'X-Requested-With': 'XMLHttpRequest'
},
mode: 'cors' // Explicitly set CORS mode
mode: 'cors'
});

if (response.redirected && response.url.includes('login')) {
showStatus('Not logged in - please log in through the main application first', true);
return false;
showResponse({
status: response.status,
statusText: response.statusText,
headers: Object.fromEntries([...response.headers.entries()]),
url: response.url
});

// Check if we're redirected to root (which means we're logged in)
if (response.redirected && response.url === `${targetServer}/`) {
showStatus('Successfully logged in - redirected to root');
return true;
}

const cookies = document.cookie;
if (!cookies) {
showStatus('Warning: No cookies present after login. Cross-origin cookies might be blocked. Make sure you are using HTTPS if required.', true);
console.log('Debug info:');
console.log('Response headers:', [...response.headers.entries()]);
console.log('Target server:', targetServer);
// Check if we have session cookie
const hasCookie = document.cookie.includes('session=') ||
response.headers.get('cookie')?.includes('session=');

if (hasCookie) {
showStatus('Session cookie present - likely logged in');
return true;
} else {
showStatus('Successfully logged in');
showStatus('Warning: No session cookie found. This could be due to:\n' +
'1. Not being logged in\n' +
'2. Cookies being blocked by browser settings\n' +
'3. SameSite cookie restrictions\n' +
'4. Different domains/subdomains\n' +
'Try accessing this page using the same hostname as your main application.', true);
return false;
}
return true;
} catch (error) {
showStatus(`Error checking login status: ${error.message}`, true);
showStatus(`Error checking login status: ${error.message}\n\n` +
'This could be due to CORS restrictions or the server being unavailable.', true);
console.error('Error:', error);
console.log('Target server:', targetServer);
return false;
}
}
Expand Down Expand Up @@ -222,6 +292,74 @@ <h1>CORS Test Page</h1>
console.error('Error:', error);
}
}

async function testPreflightRequest() {
try {
showStatus('Testing preflight request...');
const response = await fetch(`${targetServer}/auth/login`, {
method: 'OPTIONS',
credentials: 'include',
headers: {
'Accept': 'text/html',
'X-Requested-With': 'XMLHttpRequest',
'Access-Control-Request-Method': 'POST',
'Access-Control-Request-Headers': 'Content-Type'
},
mode: 'cors'
});

showResponse({
status: response.status,
statusText: response.statusText,
headers: Object.fromEntries([...response.headers.entries()]),
message: 'Preflight request successful'
});

showStatus('Successfully tested preflight request');
} catch (error) {
showStatus('Error testing preflight request: ' + error.message, true);
console.error('Error:', error);
}
}

async function testPostRequest() {
try {
showStatus('Testing POST request...');
// First try a simple POST to the login endpoint
const response = await fetch(`${targetServer}/auth/login`, {
method: 'POST',
credentials: 'include',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded',
'X-Requested-With': 'XMLHttpRequest'
},
body: 'test=true', // Simple form data
mode: 'cors'
});

const data = await response.text();
const result = {
status: response.status,
statusText: response.statusText,
headers: Object.fromEntries([...response.headers.entries()]),
response: data
};

// Even if we get a redirect or error, that's OK - we're testing CORS
if (response.status === 405) {
result.note = "The endpoint doesn't accept POST, but CORS is working (request went through)";
} else if (response.status === 302) {
result.note = "Got a redirect, which is normal. CORS is working correctly.";
}

showResponse(result);
showStatus('Successfully tested POST request - CORS is working even if endpoint returned an error');
} catch (error) {
showStatus('Error testing POST request: ' + error.message, true);
console.error('Error:', error);
}
}
</script>
</body>
</html>
85 changes: 76 additions & 9 deletions cors_test_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,91 @@
)
logger = logging.getLogger(__name__)

def get_root_domain(host):
"""Get the root domain from a hostname."""
if not host or host.lower() in ('localhost', '127.0.0.1', '::1'):
return None
# Remove port if present
domain = host.split(':')[0]
# If IP address, return as is
if domain.replace('.', '').isdigit():
return domain
# For hostnames, get root domain with leading dot
parts = domain.split('.')
if len(parts) > 2:
return '.' + '.'.join(parts[-2:]) # e.g., .example.com for sub.example.com
return '.' + domain # e.g., .localhost

class CORSHTTPRequestHandler(SimpleHTTPRequestHandler):
def end_headers(self):
# Get the origin from the request
origin = self.headers.get('Origin')
host = self.headers.get('Host')

# Log request details
logger.debug("\n=== Request Debug Info ===")
logger.debug(f"Request Path: {self.path}")
logger.debug(f"Request Origin: {origin}")
logger.debug(f"Request Host: {host}")
logger.debug("\nRequest Headers:")
for header, value in self.headers.items():
logger.debug(f" {header}: {value}")

# Set CORS headers for any origin
if origin:
logger.debug(f"Setting CORS headers for origin: {origin}")
self.send_header('Access-Control-Allow-Origin', origin)
self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
self.send_header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Accept, X-Requested-With, Cookie')
self.send_header('Access-Control-Allow-Methods', 'GET, HEAD, POST, OPTIONS')
self.send_header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Accept, Accept-Language, Content-Language, Range, X-Requested-With, Cookie, X-CSRF-Token, Upgrade-Insecure-Requests')
self.send_header('Access-Control-Allow-Credentials', 'true')
self.send_header('Access-Control-Expose-Headers', 'Set-Cookie')

self.send_header('Vary', 'Origin')

super().end_headers()

def do_GET(self):
# Handle cookie check endpoint
if self.path == '/cookie-check':
self.send_response(200)
self.send_header('Content-Type', 'application/json')

# Get cookies from request
cookies = self.headers.get('Cookie', '')
cookie_list = []
if cookies:
for cookie in cookies.split(';'):
name, value = cookie.strip().split('=', 1)
cookie_list.append({
'name': name,
'value': value[:20] + '...' if len(value) > 20 else value
})

# Log cookie information
logger.debug("\n=== Cookie Check ===")
logger.debug(f"Cookies received: {len(cookie_list)}")
for cookie in cookie_list:
logger.debug(f" {cookie['name']}: {cookie['value']}")

# Send response with cookie information
import json
response = {
'cookies_present': bool(cookie_list),
'cookie_count': len(cookie_list),
'cookies': cookie_list,
'host': self.headers.get('Host', ''),
'origin': self.headers.get('Origin', ''),
'user_agent': self.headers.get('User-Agent', '')
}
response_bytes = json.dumps(response, indent=2).encode('utf-8')

self.send_header('Content-Length', len(response_bytes))
self.end_headers()
self.wfile.write(response_bytes)
return

# Handle favicon.ico requests
if self.path == '/favicon.ico':
self.send_response(204) # No content
elif self.path == '/favicon.ico':
self.send_response(204)
self.end_headers()
return

Expand All @@ -37,11 +103,12 @@ def do_OPTIONS(self):
self.send_response(200)
self.end_headers()

def run_server(port=8087):
server_address = ('', port)
def run_server(port=8087, host='0.0.0.0'):
server_address = (host, port)
httpd = HTTPServer(server_address, CORSHTTPRequestHandler)
logger.info(f"Starting CORS test server on port {port}...")
logger.info(f"Access the test page at: http://192.168.1.51:{port}/cors_test.html")
logger.info(f"Starting CORS test server on {host}:{port}...")
logger.info(f"Access the test page using the same base domain as your main application")
logger.info(f"Example: if your app is at cli-debrid.example.com, access this at cors-test.example.com:{port}")
httpd.serve_forever()

if __name__ == '__main__':
Expand Down
Loading

0 comments on commit 3acd62f

Please sign in to comment.