1
Fork 0

Force a user interaction before token login.

This avoids issues with autoplay being disabled.
This commit is contained in:
Juliusz Chroboczek 2024-06-11 11:57:15 +02:00
parent 14aeb125be
commit 8fe2e9ca5f
4 changed files with 55 additions and 34 deletions

View File

@ -2,7 +2,9 @@ Galene 0.9.1 (unreleased)
* Added an example client with minimal functionality under static/example.
* Fixed a race condition that would cause the client to run with
undefined settings if the initial connection was extremely quick.
undefined settings if the initial connection was extremely fast.
* Changed the token login to force a user interaction in order to avoid
issues with autoplay.
* Implemented client-side timeouts (we already had one on the server side).
* Reduced the server-side timeout.
* Don't attempt to set the file descriptor limit, since recent versions

View File

@ -715,17 +715,17 @@ h1 {
font-weight: bold;
}
.userform {
.login {
display: inline
}
.userform label {
.loginform label {
min-width: 3em;
display: inline-block;
padding-top: 10px;
}
.userform input[type="text"], .userform input[type="password"] {
.loginform input[type="text"], .loginform input[type="password"] {
width: 100%;
}

View File

@ -101,10 +101,12 @@
</div>
<div class="login-container invisible" id="login-container">
<div class="login-box">
<form id="userform" class="userform">
<form id="loginform" class="loginform">
<div id="userform">
<label for="username">Username</label>
<input id="username" type="text" name="username"
autocomplete="username" class="form-control"/>
</div>
<div id="passwordform">
<label for="password">Password</label>
<input id="password" type="password" name="password"

View File

@ -35,8 +35,8 @@ let pwAuth = false;
/** @type {string} */
let token = null;
/** @type {boolean} */
let connectingAgain = false;
/** @type {string} */
let probingState = null;
/**
* @typedef {Object} settings
@ -317,8 +317,6 @@ function setConnected(connected) {
} else {
userbox.classList.add('invisible');
connectionbox.classList.remove('invisible');
if(!connectingAgain)
displayError('Disconnected', 'error');
hideVideo();
window.onresize = null;
}
@ -329,9 +327,7 @@ function setConnected(connected) {
*/
async function gotConnected() {
setConnected(true);
let again = connectingAgain;
connectingAgain = false;
await join(again);
await join();
}
/**
@ -352,10 +348,7 @@ function setChangePassword(username) {
}
}
/**
* @param {boolean} again
*/
async function join(again) {
async function join() {
let username = getInputElement('username').value.trim();
let credentials;
if(token) {
@ -364,11 +357,30 @@ async function join(again) {
type: 'token',
token: token,
};
if(!again)
// the first time around, we need to join with no username in
// order to give the server a chance to reply with 'need-username'.
switch(probingState) {
case null:
// when logging in with a token, we need to give the user
// a chance to interact with the page in order to enable
// autoplay. Probe the group first in order to determine if
// we need a username. We should really extend the protocol
// to have a simpler protocol for probing.
probingState = 'probing';
username = null;
break;
case 'need-username':
case 'success':
probingState = null;
break
default:
console.warn(`Unexpected probing state ${probingState}`);
probingState = null;
break;
}
} else {
if(probingState !== null) {
console.warn(`Unexpected probing state ${probingState}`);
probingState = null;
}
let pw = getInputElement('password').value;
getInputElement('password').value = '';
if(!groupStatus.authServer) {
@ -420,9 +432,9 @@ function gotClose(code, reason) {
if(code != 1000) {
console.warn('Socket close', code, reason);
}
let form = document.getElementById('userform');
let form = document.getElementById('loginform');
if(!(form instanceof HTMLFormElement))
throw new Error('Bad type for userform');
throw new Error('Bad type for loginform');
form.active = true;
}
@ -2471,14 +2483,13 @@ async function gotJoined(kind, group, perms, status, data, error, message) {
switch(kind) {
case 'fail':
if(error === 'need-username' || error === 'duplicate-username') {
if(probingState === 'probing' && error === 'need-username') {
probingState = 'need-username';
setVisibility('passwordform', false);
connectingAgain = true;
} else {
token = null;
}
if(error !== 'need-username')
displayError('The server said: ' + message);
}
this.close();
setButtonsVisibility();
return;
@ -2489,13 +2500,21 @@ async function gotJoined(kind, group, perms, status, data, error, message) {
return;
case 'leave':
this.close();
token = null;
setButtonsVisibility();
setChangePassword(null);
return;
case 'join':
case 'change':
if(probingState === 'probing') {
probingState = 'success';
setVisibility('userform', false);
setVisibility('passwordform', false);
this.close();
setButtonsVisibility();
return;
} else {
token = null;
}
// don't discard endPoint and friends
for(let key in status)
groupStatus[key] = status[key];
@ -2515,8 +2534,6 @@ async function gotJoined(kind, group, perms, status, data, error, message) {
return;
}
token = null;
let input = /** @type{HTMLTextAreaElement} */
(document.getElementById('input'));
input.placeholder = 'Type /help for help';
@ -3907,12 +3924,12 @@ function displayMessage(message) {
return displayError(message, "info");
}
document.getElementById('userform').onsubmit = async function(e) {
document.getElementById('loginform').onsubmit = async function(e) {
e.preventDefault();
let form = this;
if(!(form instanceof HTMLFormElement))
throw new Error('Bad type for userform');
throw new Error('Bad type for loginform');
setVisibility('passwordform', true);