Files
cloudron-box/dashboard/login.html
T

256 lines
9.7 KiB
HTML
Raw Normal View History

2023-03-13 16:46:18 +01:00
<!DOCTYPE html>
2023-03-11 17:22:27 +01:00
<html>
<head>
2023-03-13 16:46:18 +01:00
<meta charset="utf-8" />
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height" />
2024-12-13 22:29:34 +01:00
<title>{{ login.loginTo }} ##NAME##</title>
2023-03-13 16:46:18 +01:00
2024-12-13 22:29:34 +01:00
<link id="favicon" type="image/png" rel="icon" href="##ICON_URL##">
<link rel="apple-touch-icon" href="##ICON_URL##">
<link rel="icon" href="##ICON_URL##">
2023-05-11 12:15:10 +02:00
2023-03-13 16:46:18 +01:00
<!-- Theme CSS -->
2024-10-09 12:56:25 +02:00
<link type="text/css" rel="stylesheet" href="/theme.css">
2023-05-12 18:47:48 +02:00
2023-04-27 16:20:32 +02:00
<style>
body {
background-image: url('/api/v1/cloudron/background');
background-size: cover;
background-position: center;
}
2023-04-27 16:20:32 +02:00
.card {
padding: 20px;
margin-bottom: 0;
max-width: 620px;
min-height: 100%;
}
.avatar {
margin-top: 20px;
}
@media(min-width:620px) {
.card {
margin-bottom: 15px;
margin-top: 100px;
min-height: auto;
}
.avatar {
margin-top: -84px
}
}
.hide {
display: none;
}
2024-10-09 13:03:12 +02:00
#busyIndicator {
display: inline-block;
width: 15px;
height: 15px;
border: 1px solid rgba(255,255,255,.3);
border-radius: 50%;
border-top-color: #fff;
animation: spin 1s ease-in-out infinite;
margin-right: 5px;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
.btn {
display: flex;
align-items: center;
}
h1 {
padding: 0;
margin-top: 10px;
text-overflow: ellipsis;
overflow-x: hidden;
line-height: 1.5;
}
small {
display: block;
margin-top: 25px;
color: #777777;
font-size: 20px;
font-family: "Noto Sans Light", Helvetica, Arial, sans-serif;
}
2023-04-27 16:20:32 +02:00
</style>
2023-03-11 17:22:27 +01:00
</head>
<body>
<div class="layout-root hide">
2023-03-13 16:46:18 +01:00
<div class="layout-content">
2023-04-27 16:20:32 +02:00
<div class="card">
2023-03-13 16:46:18 +01:00
<div class="row">
<div class="col-md-12" style="text-align: center;">
2024-12-13 22:29:34 +01:00
<img width="128" height="128" class="avatar" src="##ICON_URL##"/>
2023-03-13 16:46:18 +01:00
<br/>
<small>{{ login.loginTo }}</small>
2024-12-13 22:29:34 +01:00
<h1>##NAME##</h1>
2023-03-11 17:22:27 +01:00
</div>
2023-03-13 16:46:18 +01:00
</div>
<br/>
<div class="row">
<div class="col-md-12">
2024-12-13 22:29:34 +01:00
##NOTE##
2023-03-13 19:08:41 +01:00
<form id="loginForm">
2023-03-13 16:46:18 +01:00
<div class="form-group">
2023-06-19 11:50:53 +02:00
<label class="control-label" for="inputUsername">{{ login.username }}</label>
2023-03-13 16:46:18 +01:00
<input type="text" class="form-control" id="inputUsername" name="username" autofocus required>
</div>
<div class="form-group">
2023-06-19 11:50:53 +02:00
<label class="control-label" for="inputPassword">{{ login.password }}</label>
2023-03-13 16:46:18 +01:00
<input type="password" class="form-control" name="password" id="inputPassword" required password-reveal>
<p class="has-error hide" id="passwordError">{{ login.errorIncorrectCredentials }}</p>
<p class="has-error hide" id="internalError">{{ login.errorInternal }}</p>
2023-03-13 16:46:18 +01:00
</div>
<div class="form-group">
2023-06-19 11:50:53 +02:00
<label class="control-label" for="inputTotpToken">{{ login.2faToken }}</label>
2023-03-13 16:46:18 +01:00
<input type="text" class="form-control" name="totpToken" id="inputTotpToken" value="">
<p class="has-error hide" id="totpError">{{ login.errorIncorrect2FAToken }}</p>
2023-03-13 16:46:18 +01:00
</div>
2023-06-19 14:08:10 +02:00
<div class="card-form-bottom-bar">
2023-06-19 13:55:58 +02:00
<a href="/passwordreset.html">{{ login.resetPasswordAction }}</a>
2024-10-09 13:03:12 +02:00
<button class="btn btn-primary btn-outline" type="submit" id="loginSubmitButton"><div id="busyIndicator" class="hide"></div> {{ login.signInAction }}</button>
2023-06-19 13:55:58 +02:00
</div>
2023-03-13 16:46:18 +01:00
</form>
2023-03-11 17:22:27 +01:00
</div>
2023-03-13 16:46:18 +01:00
</div>
</div>
</div>
2023-08-11 13:36:46 +02:00
<footer class="text-center">
2024-12-13 22:29:34 +01:00
<span class="text-muted">##FOOTER##</span>
2023-08-11 13:36:46 +02:00
</footer>
2023-03-13 16:46:18 +01:00
</div>
<script>
window.addEventListener('load', function () {
var svgEye = '<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="eye" class="svg-inline--fa fa-eye fa-w-18" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path fill="currentColor" d="M572.52 241.4C518.29 135.59 410.93 64 288 64S57.68 135.64 3.48 241.41a32.35 32.35 0 0 0 0 29.19C57.71 376.41 165.07 448 288 448s230.32-71.64 284.52-177.41a32.35 32.35 0 0 0 0-29.19zM288 400a144 144 0 1 1 144-144 143.93 143.93 0 0 1-144 144zm0-240a95.31 95.31 0 0 0-25.31 3.79 47.85 47.85 0 0 1-66.9 66.9A95.78 95.78 0 1 0 288 160z"></path></svg>';
var svgEyeSlash = '<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="eye-slash" class="svg-inline--fa fa-eye-slash fa-w-20" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><path fill="currentColor" d="M320 400c-75.85 0-137.25-58.71-142.9-133.11L72.2 185.82c-13.79 17.3-26.48 35.59-36.72 55.59a32.35 32.35 0 0 0 0 29.19C89.71 376.41 197.07 448 320 448c26.91 0 52.87-4 77.89-10.46L346 397.39a144.13 144.13 0 0 1-26 2.61zm313.82 58.1l-110.55-85.44a331.25 331.25 0 0 0 81.25-102.07 32.35 32.35 0 0 0 0-29.19C550.29 135.59 442.93 64 320 64a308.15 308.15 0 0 0-147.32 37.7L45.46 3.37A16 16 0 0 0 23 6.18L3.37 31.45A16 16 0 0 0 6.18 53.9l588.36 454.73a16 16 0 0 0 22.46-2.81l19.64-25.27a16 16 0 0 0-2.82-22.45zm-183.72-142l-39.3-30.38A94.75 94.75 0 0 0 416 256a94.76 94.76 0 0 0-121.31-92.21A47.65 47.65 0 0 1 304 192a46.64 46.64 0 0 1-1.54 10l-73.61-56.89A142.31 142.31 0 0 1 320 112a143.92 143.92 0 0 1 144 144c0 21.63-5.29 41.79-13.9 60.11z"></path></svg>';
document.querySelectorAll('[password-reveal]').forEach(function (element) {
var eye = document.createElement('i');
eye.innerHTML = svgEyeSlash;
eye.style.width = '18px';
eye.style.height = '18px';
eye.style.position = 'relative';
eye.style.float = 'right';
eye.style.marginTop = '-24px';
eye.style.marginRight = '10px';
eye.style.cursor = 'pointer';
eye.addEventListener('click', function () {
if (element.type === 'password') {
element.type = 'text';
eye.innerHTML = svgEye;
} else {
element.type = 'password';
eye.innerHTML = svgEyeSlash;
}
});
element.parentNode.style.position = 'relative';
element.parentNode.insertBefore(eye, element.nextSibling);
});
});
2023-03-13 19:08:41 +01:00
document.getElementById('loginForm').addEventListener('submit', function (event) {
event.preventDefault();
document.getElementById('passwordError').classList.add('hide');
document.getElementById('totpError').classList.add('hide');
document.getElementById('internalError').classList.add('hide');
2024-01-03 14:27:01 +01:00
document.getElementById('busyIndicator').classList.remove('hide');
2023-05-12 14:31:26 +02:00
2024-12-13 22:29:34 +01:00
const apiUrl = '##SUBMIT_URL##';
2023-03-13 19:08:41 +01:00
const body = {
2023-03-13 19:08:41 +01:00
username: document.getElementById('inputUsername').value,
password: document.getElementById('inputPassword').value,
totpToken: document.getElementById('inputTotpToken').value
};
2023-05-12 14:31:26 +02:00
let res;
2023-03-13 19:08:41 +01:00
fetch(apiUrl, {
method: 'POST',
2023-03-13 19:08:41 +01:00
body: JSON.stringify(body),
headers: { 'Content-type': 'application/json; charset=UTF-8' }
}).then(function (response) {
2023-05-12 14:31:26 +02:00
res = response;
return res.json(); // we always return objects
2023-03-13 19:08:41 +01:00
}).then(function (data) {
if (res.status === 410) {
// the oidc login session is old
window.location.reload();
} else if (res.status === 401) {
if (data.message.indexOf('totpToken') !== -1) {
document.getElementById('inputTotpToken').value = '';
document.getElementById('inputTotpToken').focus();
document.getElementById('totpError').classList.remove('hide');
2023-05-12 14:31:26 +02:00
} else {
document.getElementById('inputPassword').value = '';
document.getElementById('inputPassword').focus();
document.getElementById('passwordError').classList.remove('hide');
2023-05-12 14:31:26 +02:00
}
2024-01-03 14:27:01 +01:00
document.getElementById('busyIndicator').classList.add('hide');
return;
2023-05-12 14:31:26 +02:00
} else if (res.status !== 200) {
2024-01-03 14:27:01 +01:00
document.getElementById('busyIndicator').classList.add('hide');
2023-05-12 14:31:26 +02:00
throw new Error('Something went wrong');
}
if (data.redirectTo) window.location.href = data.redirectTo;
else console.log('login success but missing redirectTo in data:', data);
2023-03-13 19:08:41 +01:00
}).catch(function (error) {
document.getElementById('internalError').classList.remove('hide');
2024-01-03 14:27:01 +01:00
document.getElementById('busyIndicator').classList.add('hide');
2023-05-12 14:31:26 +02:00
console.warn(error, res);
2023-03-13 19:08:41 +01:00
});
});
2023-03-13 16:46:18 +01:00
2024-04-03 18:23:29 +02:00
// placed in local storage by setupaccount.js
const autoLoginToken = localStorage.cloudronFirstTimeToken;
if (autoLoginToken) {
2024-12-13 22:29:34 +01:00
const apiUrl = '##SUBMIT_URL##';
let res;
fetch(apiUrl, {
method: 'POST',
2024-04-03 18:23:29 +02:00
body: JSON.stringify({ autoLoginToken }),
headers: { 'Content-type': 'application/json; charset=UTF-8' }
2024-04-04 10:29:36 +02:00
}).then(function (res) {
localStorage.removeItem('cloudronFirstTimeToken');
return res.json(); // we always return objects
}).then(function (data) {
if (data.redirectTo) window.location.href = data.redirectTo;
else console.log('login success but missing redirectTo in data:', data);
}).catch(function (error) {
document.getElementsByClassName('layout-root')[0].classList.remove('hide');
2024-04-04 10:29:36 +02:00
localStorage.removeItem('cloudronFirstTimeToken');
document.getElementById('internalError').classList.remove('hide');
document.getElementById('busyIndicator').classList.add('hide');
console.warn(error, res);
});
} else {
document.getElementsByClassName('layout-root')[0].classList.remove('hide');
}
2023-03-13 16:46:18 +01:00
</script>
2023-03-11 17:22:27 +01:00
</body>
</html>