Redo auth flow with lit. Beef up the test a bit, accordingly.

git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4392 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
Cory McWilliams 2023-08-09 22:38:41 +00:00
parent 1ba37d95b5
commit 70d37c88b5
4 changed files with 150 additions and 75 deletions

View File

@ -10,10 +10,109 @@
<link type="text/css" rel="stylesheet" href="/static/style.css"> <link type="text/css" rel="stylesheet" href="/static/style.css">
<link type="image/png" rel="shortcut icon" href="/static/favicon.png"> <link type="image/png" rel="shortcut icon" href="/static/favicon.png">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<!--HEAD-->
</head> </head>
<body> <body>
<h1 style="text-align: center">Tilde Friends Sign-in</h1> <h1 style="text-align: center">Tilde Friends Sign-in</h1>
<div id="content"><!--SESSION--></div> <tf-auth id="auth"></tf-auth>
<script>window.litDisableBundleWarning = true;</script>
<script type="module">
import {LitElement, html} from '/static/lit/lit-all.min.js';
let g_data = $AUTH_DATA;
let app = document.getElementById('auth');
Object.assign(app, g_data);
class TfAuthElement extends LitElement {
static get_properties() {
return {
name: {type: String},
tab: {type: String},
};
}
constructor() {
super();
this.tab = 'login';
}
tab_changed(name) {
this.tab = name;
this.requestUpdate();
}
render() {
let self = this;
return html`
<style>
[name="tab"] {
display: none;
}
[name="tab"]+label {
background-color: #657b83;
padding: 1em;
display: inline-block;
flex: 1 0;
text-align: center;
cursor: pointer;
}
[name="tab"]+label:hover {
background-color: #dc322f;
}
[name="tab"]:checked+label {
background-color: #93a1a1;
}
.error {
color: #f00;
border: 1px solid #f00;
margin: 4px;
padding: 8px;
}
</style>
<div style="display: flex; flex-direction: column">
<h1 ?hidden=${this.name}>Welcome.</h1>
<h1 ?hidden=${this.name === undefined}>Welcome, ${this.name}.</h1>
<div style="display: flex; flex-direction: row; width: 100%">
<input type="radio" name="tab" id="login" value="Login" ?checked=${this.tab == 'login'} @change=${() => self.tab_changed('login')}></input>
<label for="login" id="login_label">Login</label>
<input type="radio" name="tab" id="register" value="Register" ?checked=${this.tab == 'register'} @change=${() => self.tab_changed('register')}></input>
<label for="register" id="register_label">Register</label>
<input type="radio" name="tab" id="guest" value="Guest" ?checked=${this.tab == 'guest'} @change=${() => self.tab_changed('guest')}></input>
<label for="guest" id="guest_label">Guest</label>
</div>
<div ?hidden=${this.tab != 'login' && this.tab != 'register'}>
<div id="error" ?hidden=${this.error === undefined} class="error">
${this.error}
</div>
<form method="POST">
<div><label for="name">Name:</label> <input type="text" id="name" name="name" value=""></div>
<div><label for="password">Password:</label> <input type="password" id="password" name="password" value=""></div>
<div ?hidden=${this.tab != 'register'} id="confirmPassword"><label for="confirm">Confirm:</label> <input type="password" id="confirm" name="confirm" value=""></div>
<div><input id="loginButton" type="submit" name="submit" value="Login"></div>
<input type="hidden" name="register" value="${this.tab == 'register' ? 1 : 0}"></input>
</form>
</div>
<div ?hidden=${this.tab != 'guest'}>
<form method="POST">
<input type="submit" id="guestButton" name="guestButton" value="Proceed as Guest"></input>
</form>
</div>
<div ?hidden=${this.have_administrator} class="notice">
There is currently no administrator. You will be made administrator.
</div>
<h2>Code of Conduct</h2>
<div>
<textarea readonly rows="20" cols="80">${this.code_of_conduct}</textarea>
</div>
</div>
`;
}
}
customElements.define('tf-auth', TfAuthElement);
</script>
</body> </body>
</html> </html>

View File

@ -121,6 +121,7 @@ function handler(request, response) {
let formData = form.decodeForm(request.query); let formData = form.decodeForm(request.query);
print(request.method, utf8Decode(request.body), JSON.stringify(formData));
if (request.method == "POST" || formData.submit) { if (request.method == "POST" || formData.submit) {
sessionIsNew = true; sessionIsNew = true;
formData = form.decodeForm(utf8Decode(request.body), formData); formData = form.decodeForm(utf8Decode(request.body), formData);
@ -178,46 +179,16 @@ function handler(request, response) {
} else { } else {
File.readFile("core/auth.html").then(function(data) { File.readFile("core/auth.html").then(function(data) {
let html = utf8Decode(data); let html = utf8Decode(data);
let contents = ""; let auth_data = {
session_is_new: sessionIsNew,
if (entry) { name: entry?.name,
if (sessionIsNew) { error: loginError,
contents += '<div>Welcome back, ' + entry.name + '.</div>\n'; code_of_conduct: core.globalSettings.code_of_conduct,
} else { have_administrator: !noAdministrator(),
contents += '<div>You are already logged in, ' + entry.name + '.</div>\n'; };
} html = utf8Encode(html.replace('$AUTH_DATA', JSON.stringify(auth_data)));
contents += '<div><a href="/login/logout">Logout</a></div>\n'; response.writeHead(200, {"Content-Type": "text/html; charset=utf-8", "Set-Cookie": cookie, "Content-Length": html.length});
} else { response.end(html);
contents += '<form method="POST">\n';
if (loginError) {
contents += "<p>" + loginError + "</p>\n";
}
contents += '<div id="auth_greeting"><b>Halt. Who goes there?</b></div>\n'
contents += '<div id="auth">\n';
contents += '<div id="auth_login">\n'
if (noAdministrator()) {
contents += '<div class="notice">There is currently no administrator. You will be made administrator.</div>\n';
}
contents += '<div><label for="name">Name:</label> <input type="text" id="name" name="name" value=""></div>\n';
contents += '<div><label for="password">Password:</label> <input type="password" id="password" name="password" value=""></div>\n';
contents += '<div id="confirmPassword" style="display: none"><label for="confirm">Confirm:</label> <input type="password" id="confirm" name="confirm" value=""></div>\n';
contents += '<div><input type="checkbox" id="register" name="register" value="1" onchange="showHideConfirm()"> <label for="register">Register a new account</label></div>\n';
contents += '<div><input id="loginButton" type="submit" name="submit" value="Login"></div>\n';
contents += '</div>';
contents += '<div class="auth_or"> - or - </div>';
contents += '<div id="auth_guest">\n';
contents += '<input id="guestButton" type="submit" name="submit" value="Proceeed as Guest">\n';
contents += '</div>\n';
contents += '</div>\n';
contents += '<div style="text-align: center">\n';
contents += '<h2>Code of Conduct</h2>\n';
contents += `<div><textarea readonly rows=20 cols=80>${core.globalSettings.code_of_conduct}</textarea></div>\n`;
contents += '</div>\n';
contents += '</form>';
}
let text = html.replace("<!--SESSION-->", contents);
response.writeHead(200, {"Content-Type": "text/html; charset=utf-8", "Set-Cookie": cookie, "Content-Length": text.length});
response.end(text);
}).catch(function(error) { }).catch(function(error) {
response.writeHead(404, {"Content-Type": "text/plain; charset=utf-8", "Connection": "close"}); response.writeHead(404, {"Content-Type": "text/plain; charset=utf-8", "Connection": "close"});
response.end("404 File not found"); response.end("404 File not found");

View File

@ -100,33 +100,6 @@ a:active {
float: right; float: right;
} }
#auth_greeting {
text-align: center;
}
#auth {
display: flex;
flex-flow: row;
align-content: center;
align-items: center;
text-align: center;
justify-content: center;
}
#auth_login {
flex: 0 1 auto;
text-align: right;
}
.auth_or {
flex: 0 1 auto;
padding: 1em;
}
#auth_guest {
flex: 0 1 auto;
}
.notice { .notice {
color: #cb4b16; color: #cb4b16;
margin: 1em; margin: 1em;

View File

@ -23,19 +23,21 @@ try:
options = webdriver.FirefoxOptions() options = webdriver.FirefoxOptions()
#options.add_argument('--headless') #options.add_argument('--headless')
driver = webdriver.Firefox(options = options) driver = webdriver.Firefox(options = options)
wait = WebDriverWait(driver, 30) wait = WebDriverWait(driver, 10)
driver.get('http://localhost:8888') driver.get('http://localhost:8888')
driver.find_element(By.TAG_NAME, 'tf-navigation').shadow_root.find_element(By.LINK_TEXT, 'login').click() driver.find_element(By.TAG_NAME, 'tf-navigation').shadow_root.find_element(By.LINK_TEXT, 'login').click()
driver.find_element(By.ID, 'register').click() driver.find_element(By.TAG_NAME, 'tf-auth').shadow_root.find_element(By.ID, 'register_label').click()
driver.find_element(By.ID, 'name').send_keys('test_user') driver.find_element(By.TAG_NAME, 'tf-auth').shadow_root.find_element(By.ID, 'name').send_keys('test_user')
driver.find_element(By.ID, 'password').send_keys('test_password') driver.find_element(By.TAG_NAME, 'tf-auth').shadow_root.find_element(By.ID, 'password').send_keys('test_password')
driver.find_element(By.ID, 'confirm').send_keys('test_password') driver.find_element(By.TAG_NAME, 'tf-auth').shadow_root.find_element(By.ID, 'confirm').send_keys('test_password')
driver.find_element(By.ID, 'loginButton').click() driver.find_element(By.TAG_NAME, 'tf-auth').shadow_root.find_element(By.ID, 'loginButton').click()
wait.until(expected_conditions.presence_of_element_located((By.ID, 'document')))
driver.switch_to.frame(driver.find_element(By.ID, 'document')) driver.switch_to.frame(driver.find_element(By.ID, 'document'))
wait.until(expected_conditions.presence_of_element_located((By.LINK_TEXT, 'ssb'))).click() wait.until(expected_conditions.presence_of_element_located((By.LINK_TEXT, 'ssb'))).click()
driver.switch_to.default_content() driver.switch_to.default_content()
wait.until(expected_conditions.presence_of_element_located((By.ID, 'content')))
driver.switch_to.frame(wait.until(expected_conditions.presence_of_element_located((By.ID, 'document')))) driver.switch_to.frame(wait.until(expected_conditions.presence_of_element_located((By.ID, 'document'))))
tf_app = wait.until(expected_conditions.presence_of_element_located((By.TAG_NAME, 'tf-app'))).shadow_root tf_app = wait.until(expected_conditions.presence_of_element_located((By.TAG_NAME, 'tf-app'))).shadow_root
wait.until(expected_conditions.element_to_be_clickable(tf_app.find_element(By.ID, 'create_identity'))).click() wait.until(expected_conditions.element_to_be_clickable(tf_app.find_element(By.ID, 'create_identity'))).click()
@ -48,6 +50,36 @@ try:
driver.switch_to.default_content() driver.switch_to.default_content()
driver.find_element(By.ID, 'allow').click() driver.find_element(By.ID, 'allow').click()
driver.find_element(By.TAG_NAME, 'tf-navigation').shadow_root.find_element(By.LINK_TEXT, 'logout test_user').click()
driver.find_element(By.TAG_NAME, 'tf-auth').shadow_root.find_element(By.ID, 'login_label').click()
driver.find_element(By.TAG_NAME, 'tf-auth').shadow_root.find_element(By.ID, 'name').send_keys('test_user')
driver.find_element(By.TAG_NAME, 'tf-auth').shadow_root.find_element(By.ID, 'password').send_keys('test_password')
driver.find_element(By.TAG_NAME, 'tf-auth').shadow_root.find_element(By.ID, 'loginButton').click()
wait.until(expected_conditions.presence_of_element_located((By.ID, 'content')))
driver.find_element(By.TAG_NAME, 'tf-navigation').shadow_root.find_element(By.LINK_TEXT, 'logout test_user').click()
driver.find_element(By.TAG_NAME, 'tf-auth').shadow_root.find_element(By.ID, 'guest_label').click()
driver.find_element(By.TAG_NAME, 'tf-auth').shadow_root.find_element(By.ID, 'guestButton').click()
wait.until(expected_conditions.presence_of_element_located((By.ID, 'content')))
driver.switch_to.frame(wait.until(expected_conditions.presence_of_element_located((By.ID, 'document'))))
wait.until(expected_conditions.presence_of_element_located((By.TAG_NAME, 'tf-app'))).shadow_root
driver.switch_to.default_content()
driver.find_element(By.TAG_NAME, 'tf-navigation').shadow_root.find_element(By.LINK_TEXT, 'logout guest').click()
driver.find_element(By.TAG_NAME, 'tf-auth').shadow_root.find_element(By.ID, 'login_label').click()
driver.find_element(By.TAG_NAME, 'tf-auth').shadow_root.find_element(By.ID, 'name').send_keys('test_user')
driver.find_element(By.TAG_NAME, 'tf-auth').shadow_root.find_element(By.ID, 'password').send_keys('wrong_password')
driver.find_element(By.TAG_NAME, 'tf-auth').shadow_root.find_element(By.ID, 'loginButton').click()
driver.find_element(By.TAG_NAME, 'tf-auth').shadow_root.find_element(By.ID, 'error')
driver.find_element(By.TAG_NAME, 'tf-auth').shadow_root.find_element(By.ID, 'name').send_keys('wrong_user')
driver.find_element(By.TAG_NAME, 'tf-auth').shadow_root.find_element(By.ID, 'password').send_keys('test_password')
driver.find_element(By.TAG_NAME, 'tf-auth').shadow_root.find_element(By.ID, 'loginButton').click()
driver.find_element(By.TAG_NAME, 'tf-auth').shadow_root.find_element(By.ID, 'error')
print('SUCCESS.') print('SUCCESS.')
finally: finally:
driver.close() driver.close()