Files
titlebot-ng-ng/voteServer/htm/matrix-login.html
T

150 lines
5.4 KiB
HTML
Raw Normal View History

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sign in with Matrix</title>
<link rel="stylesheet" href="css.css">
</head>
<body>
<h1>Sign in with Matrix</h1>
<p>Log in with your Matrix account to vote.</p>
<div id="login_form">
<label for="homeserver">Homeserver:</label>
<input type="text" id="homeserver" placeholder="https://matrix.org">
<label for="username">Username:</label>
<input type="text" id="username" placeholder="@username:matrix.org">
<label for="password">Password:</label>
<input type="password" id="password" placeholder="Password">
<button id="login_btn" onclick="matrixLogin()">Sign In</button>
<div id="status"></div>
</div>
<a id="back_link" href="../">Back to voting page</a>
<script>
async function init() {
const parts = window.location.pathname.split('/').filter(Boolean);
const slug = parts[0];
if (!slug) {
setStatus('Invalid URL. Go to the voting page first.', true);
return;
}
try {
const resp = await fetch('/' + slug + '/roomConfig');
if (resp.ok) {
const config = await resp.json();
document.getElementById('homeserver').value = config.homeserver || 'https://matrix.org';
}
} catch (e) {
document.getElementById('homeserver').value = 'https://matrix.org';
}
const sessionToken = sessionStorage.getItem('matrix_session_token');
if (sessionToken) {
window.location.href = '/' + slug + '/';
}
}
async function matrixLogin() {
const homeserver = document.getElementById('homeserver').value.trim().replace(/\/+$/, '');
const username = document.getElementById('username').value.trim();
const password = document.getElementById('password').value;
if (!homeserver || !username || !password) {
setStatus('All fields are required.', true);
return;
}
setStatus('Checking homeserver...');
document.getElementById('login_btn').disabled = true;
try {
const loginTypesResp = await fetch(homeserver + '/_matrix/client/v3/login');
if (!loginTypesResp.ok) {
setStatus('Could not reach homeserver. Check the URL.', true);
document.getElementById('login_btn').disabled = false;
return;
}
const loginTypes = await loginTypesResp.json();
const supportsPassword = loginTypes.flows && loginTypes.flows.some(f => f.type === 'm.login.password');
if (!supportsPassword) {
setStatus('This homeserver does not support password login. Try the Nostr option instead.', true);
document.getElementById('login_btn').disabled = false;
return;
}
setStatus('Logging in...');
const loginResp = await fetch(homeserver + '/_matrix/client/v3/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
type: 'm.login.password',
identifier: { type: 'm.id.user', user: username },
password: password
})
});
if (!loginResp.ok) {
setStatus('Login failed: ' + (loginResp.status === 403 ? 'Invalid credentials' : 'Homeserver error'), true);
document.getElementById('login_btn').disabled = false;
return;
}
const loginData = await loginResp.json();
const accessToken = loginData.access_token;
setStatus('Verifying identity...');
const parts = window.location.pathname.split('/').filter(Boolean);
const slug = parts[0];
const authResp = await fetch('/' + slug + '/matrixAuth', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
access_token: accessToken,
homeserver: homeserver
})
});
if (!authResp.ok) {
const errText = await authResp.text();
setStatus('Verification failed: ' + errText, true);
document.getElementById('login_btn').disabled = false;
return;
}
const authData = await authResp.json();
sessionStorage.setItem('matrix_session_token', authData.session_token);
window.location.href = '/' + slug + '/';
} catch (err) {
setStatus('Error: ' + err.message, true);
document.getElementById('login_btn').disabled = false;
}
}
function setStatus(msg, isError) {
const el = document.getElementById('status');
el.innerHTML = msg;
el.className = isError ? 'error' : 'success';
}
init();
</script>
</body>
</html>