runegate 0.3.1

Lightweight Rust-based identity proxy
Documentation
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Runegate Login</title>
    
    <!-- Favicon -->    
    <link rel="icon" href="img/favicon/favicon.svg" type="image/svg+xml">
    <link rel="icon" type="image/png" sizes="192x192" href="img/favicon/favicon-192x192.png">
    <link rel="icon" type="image/png" sizes="48x48" href="img/favicon/favicon-48x48.png">
    <link rel="icon" type="image/png" sizes="32x32" href="img/favicon/favicon-32x32.png">
    <link rel="icon" type="image/png" sizes="16x16" href="img/favicon/favicon-16x16.png">
    <link rel="icon" href="img/favicon/favicon.ico">
    <link rel="manifest" href="img/favicon/site.webmanifest">
    <style>
        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
            background-color: #f7f9fc;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            margin: 0;
            padding: 20px;
        }
        .login-container {
            background: white;
            border-radius: 8px;
            box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
            width: 100%;
            max-width: 400px;
            padding: 40px;
            text-align: center;
        }
        h1 {
            color: #2c3e50;
            margin-bottom: 30px;
        }
        .form-group {
            margin-bottom: 20px;
        }
        input {
            width: 100%;
            padding: 12px;
            border: 1px solid #ddd;
            border-radius: 4px;
            font-size: 16px;
            box-sizing: border-box;
        }
        button {
            background-color: #0AB0B0; /* Darker teal shade of #0CD6D6 */
            color: white;
            border: none;
            border-radius: 4px;
            padding: 12px 20px;
            font-size: 16px;
            cursor: pointer;
            width: 100%;
            transition: background-color 0.3s;
        }
        button:hover {
            background-color: #098A8A; /* Even darker on hover */
        }
        .message {
            display: none;
            margin-top: 20px;
            padding: 10px;
            border-radius: 4px;
        }
        .logo {
            max-width: 150px;
            margin-bottom: 20px;
        }
        .success {
            background-color: #d4edda;
            color: #155724;
        }
        .error {
            background-color: #f8d7da;
            color: #721c24;
        }
        .logo {
            max-width: 100px;
            margin-bottom: 20px;
        }
    </style>
</head>
<body>
    <div class="login-container">
        <img src="img/runegate-logo.svg" alt="Runegate Logo" class="logo">
        <h1><span style="color: #0CD6D6">R</span><span style="color: #444">UNE</span><span style="color: #0CD6D6">G</span><span style="color: #444">ATE</span></h1>
        <p>Enter your email address to receive a magic link</p>
        
        <div class="form-group">
            <input type="email" id="email" placeholder="your@email.com" required>
        </div>
        
        <button id="login-button">Send Magic Link</button>
        
        <div id="message" class="message"></div>
    </div>

    <script>
        // Get base path for API requests - detects if we're behind a proxy
        function getBasePath() {
            // Extract the base path from the current URL
            const path = window.location.pathname;
            // If we're directly at /login.html, use root path
            if (path === '/login.html') {
                return '';
            }
            // If we're behind a proxy (e.g., /proxyurl/login.html), extract the base path
            const match = path.match(/^(\/[^\/]+)\//); 
            return match ? match[1] : '';
        }

        document.getElementById('login-button').addEventListener('click', async () => {
            const email = document.getElementById('email').value;
            const messageElement = document.getElementById('message');
            const basePath = getBasePath();
            
            if (!email || !email.includes('@')) {
                messageElement.textContent = 'Please enter a valid email address';
                messageElement.className = 'message error';
                messageElement.style.display = 'block';
                return;
            }
            
            try {
                const response = await fetch(`${basePath}/login`, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    body: JSON.stringify({ email })
                });
                
                if (response.ok) {
                    messageElement.textContent = 'Magic link sent! Please check your email.';
                    messageElement.className = 'message success';
                } else {
                    const errorText = await response.text();
                    messageElement.textContent = `Error: ${errorText}`;
                    messageElement.className = 'message error';
                }
            } catch (error) {
                messageElement.textContent = `Error: ${error.message}`;
                messageElement.className = 'message error';
            }
            
            messageElement.style.display = 'block';
        });
    </script>
</body>
</html>