mirror of
https://github.com/sol1/rustguac.git
synced 2026-09-10 17:47:13 +00:00
02f93fe67a
SSO button is now the primary action on the login page — larger, bolder, and displayed first. API key login is hidden behind a chevron toggle for admin use. Falls back to showing the API key form directly when OIDC is not configured. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
194 lines
7.1 KiB
HTML
194 lines
7.1 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>rustguac</title>
|
|
<style>
|
|
:root { --primary: #e94560; --primary-hover: #c73652; --accent: #5bc0be; --accent-hover: #4aa3a1; --bg: #1a1a2e; --surface: #16213e; --input: #0f3460; --text: #e0e0e0; --text-muted: #aaa; --border: #333; }
|
|
body { font-family: monospace; background: var(--bg); color: var(--text); padding: 2em; font-size: 18px; }
|
|
h1 { color: var(--primary); }
|
|
#error { color: var(--primary); margin-top: 0.8em; }
|
|
|
|
.login-container { max-width: 360px; margin: 2em 0; }
|
|
|
|
#sso-section {
|
|
display: none;
|
|
margin-bottom: 1.5em;
|
|
}
|
|
#sso-btn {
|
|
width: 100%;
|
|
padding: 0.8em;
|
|
background: var(--accent);
|
|
color: var(--bg);
|
|
border: none;
|
|
font-family: monospace;
|
|
font-size: 1.2em;
|
|
font-weight: bold;
|
|
border-radius: 6px;
|
|
cursor: pointer;
|
|
}
|
|
#sso-btn:hover { background: var(--accent-hover); }
|
|
|
|
.api-key-toggle {
|
|
color: var(--text-muted);
|
|
font-size: 0.85em;
|
|
cursor: pointer;
|
|
user-select: none;
|
|
margin-top: 1em;
|
|
display: none;
|
|
}
|
|
.api-key-toggle:hover { color: var(--text); }
|
|
.api-key-toggle .chevron {
|
|
display: inline-block;
|
|
transition: transform 0.2s;
|
|
margin-right: 0.3em;
|
|
}
|
|
.api-key-toggle .chevron.open { transform: rotate(90deg); }
|
|
|
|
#login-form {
|
|
background: var(--surface);
|
|
padding: 1.5em;
|
|
border-radius: 6px;
|
|
margin-top: 0.5em;
|
|
}
|
|
#login-form label { display: block; margin-top: 0.8em; color: var(--text-muted); font-size: 0.9em; }
|
|
#login-form input {
|
|
display: block;
|
|
width: 100%;
|
|
padding: 0.4em;
|
|
margin-top: 0.2em;
|
|
background: var(--input);
|
|
border: 1px solid var(--border);
|
|
color: var(--text);
|
|
font-family: monospace;
|
|
font-size: 1em;
|
|
border-radius: 3px;
|
|
box-sizing: border-box;
|
|
}
|
|
#login-form input:focus { outline: none; border-color: var(--primary); }
|
|
#login-form button {
|
|
margin-top: 1.2em;
|
|
padding: 0.5em 1.5em;
|
|
background: var(--primary);
|
|
color: #fff;
|
|
border: none;
|
|
font-family: monospace;
|
|
font-size: 1em;
|
|
border-radius: 3px;
|
|
cursor: pointer;
|
|
}
|
|
#login-form button:hover { background: var(--primary-hover); }
|
|
#login-form button:disabled { background: #555; cursor: default; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<img id="site-logo" src="/logo.svg" style="max-height:64px;margin-bottom:0.5em" alt="">
|
|
<h1>rustguac</h1>
|
|
|
|
<div class="login-container">
|
|
<div id="sso-section">
|
|
<button id="sso-btn">Sign in with SSO</button>
|
|
</div>
|
|
|
|
<div class="api-key-toggle" id="api-key-toggle">
|
|
<span class="chevron" id="api-key-chevron">▶</span> Sign in with API key
|
|
</div>
|
|
|
|
<form id="login-form">
|
|
<strong>Login</strong>
|
|
<label>API Key
|
|
<input type="password" id="api-key" placeholder="Bearer API key" required>
|
|
</label>
|
|
<button type="submit" id="login-btn">Login</button>
|
|
<div id="error"></div>
|
|
</form>
|
|
</div>
|
|
|
|
<script>
|
|
// Show SSO error if redirected back from a failed callback
|
|
if (new URLSearchParams(window.location.search).get('sso_error')) {
|
|
document.getElementById('error').textContent = 'SSO login failed — please try again.';
|
|
history.replaceState(null, '', '/');
|
|
}
|
|
|
|
// If already logged in via API key, redirect
|
|
if (sessionStorage.getItem('rustguac_api_key')) {
|
|
window.location.href = '/addressbook.html';
|
|
}
|
|
|
|
// Check if already authenticated via cookie
|
|
fetch('/api/me', { credentials: 'same-origin' })
|
|
.then(function(res) {
|
|
if (res.ok) window.location.href = '/addressbook.html';
|
|
});
|
|
|
|
function applyTheme(theme) {
|
|
if (!theme) return;
|
|
var props = {primary_color:'--primary',primary_hover:'--primary-hover',accent_color:'--accent',accent_hover:'--accent-hover',bg_color:'--bg',surface_color:'--surface',input_color:'--input',text_color:'--text',text_muted:'--text-muted',border_color:'--border'};
|
|
var r = document.documentElement.style;
|
|
for (var k in props) { if (theme[k]) r.setProperty(props[k], theme[k]); }
|
|
if (theme.logo_url) { var logo = document.getElementById('site-logo'); if (logo) { logo.src = theme.logo_url; logo.style.display = ''; } }
|
|
}
|
|
|
|
var loginForm = document.getElementById('login-form');
|
|
var apiKeyToggle = document.getElementById('api-key-toggle');
|
|
var chevron = document.getElementById('api-key-chevron');
|
|
|
|
// Check if OIDC is enabled
|
|
fetch('/api/auth/status')
|
|
.then(function(res) { return res.json(); })
|
|
.then(function(data) {
|
|
if (data.oidc_enabled) {
|
|
document.getElementById('sso-section').style.display = 'block';
|
|
apiKeyToggle.style.display = 'block';
|
|
// Hide API key form by default when SSO is available
|
|
loginForm.style.display = 'none';
|
|
}
|
|
if (data.site_title) {
|
|
document.title = data.site_title;
|
|
document.querySelector('h1').textContent = data.site_title;
|
|
}
|
|
applyTheme(data.theme);
|
|
});
|
|
|
|
document.getElementById('sso-btn').addEventListener('click', function() {
|
|
window.location.href = '/auth/login';
|
|
});
|
|
|
|
// Toggle API key form
|
|
apiKeyToggle.addEventListener('click', function() {
|
|
var hidden = loginForm.style.display === 'none';
|
|
loginForm.style.display = hidden ? '' : 'none';
|
|
chevron.className = hidden ? 'chevron open' : 'chevron';
|
|
});
|
|
|
|
var errorEl = document.getElementById('error');
|
|
var btn = document.getElementById('login-btn');
|
|
|
|
loginForm.addEventListener('submit', function(e) {
|
|
e.preventDefault();
|
|
errorEl.textContent = '';
|
|
btn.disabled = true;
|
|
btn.textContent = 'Checking...';
|
|
|
|
var key = document.getElementById('api-key').value;
|
|
fetch('/api/sessions', {
|
|
headers: { 'Authorization': 'Bearer ' + key }
|
|
})
|
|
.then(function(res) {
|
|
if (!res.ok) throw new Error('Invalid API key');
|
|
sessionStorage.setItem('rustguac_api_key', key);
|
|
window.location.href = '/addressbook.html';
|
|
})
|
|
.catch(function(err) {
|
|
errorEl.textContent = err.message;
|
|
})
|
|
.finally(function() {
|
|
btn.disabled = false;
|
|
btn.textContent = 'Login';
|
|
});
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|