150 lines
5.4 KiB
HTML
150 lines
5.4 KiB
HTML
<!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>
|