summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgumi <git@gumi.ca>2018-10-31 14:31:06 -0400
committergumi <git@gumi.ca>2018-10-31 15:47:52 -0400
commitcae9e1bc617f78d656ad4814c230b8cc6db37d15 (patch)
tree12a69779d1e08720425a77b7c45e842c4170b13a
parent3c0b154cd2ca152761b2507f8a4105fe0ca98904 (diff)
downloadlanding-cae9e1bc617f78d656ad4814c230b8cc6db37d15.tar.gz
landing-cae9e1bc617f78d656ad4814c230b8cc6db37d15.tar.bz2
landing-cae9e1bc617f78d656ad4814c230b8cc6db37d15.tar.xz
landing-cae9e1bc617f78d656ad4814c230b8cc6db37d15.zip
add a password reset form
-rw-r--r--src/register.html69
-rw-r--r--src/reset.html313
2 files changed, 357 insertions, 25 deletions
diff --git a/src/register.html b/src/register.html
index 6842475..32b65bc 100644
--- a/src/register.html
+++ b/src/register.html
@@ -124,11 +124,6 @@
border: 1px solid #aaa;
}
- .grecaptcha-badge {
- margin-bottom: 2em;
- margin-top: 2em;
- }
-
.container > form.error .status {
display: block!important;
}
@@ -138,6 +133,10 @@
background-color: #FDD!important;
}
+ /*input:focus:required:valid {
+ background-color: greenyellow!important;
+ }*/
+
.warning {
color: #fff;
margin: 1em;
@@ -195,34 +194,35 @@
<input name="email" placeholder="Email Address (optional)" type="email" maxlength="39" tabindex="3">
</fieldset>
<fieldset>
- <div>
- <button
- class="g-recaptcha"
+ <div class="g-recaptcha"
data-sitekey="6LdaVUcUAAAAAJ-7cORTu4cZCPSNjDqjz3y4nLVR"
- data-callback="onSubmit"
- data-badge="inline"
- data-submit="...Sending"
- type="submit">Submit</button>
+ data-callback="onCaptchaCompletion"
+ data-size="invisible">
+ </div>
+ <div>
+ <button type="submit">Submit</button>
</div>
</fieldset>
</form>
</div>
<script>
+ var recaptcha_loaded = false;
+
const nodes = {
uname: document.querySelector("input[name=username]"),
pwd: document.querySelector("input[name=password]"),
email: document.querySelector("input[name=email]"),
form: document.querySelector(".container > form"),
status: document.querySelector(".status"),
- captcha: undefined
+ button: document.querySelector(".container > form button"),
};
const validateInput = node => {
node.setCustomValidity("");
- if (node.checkValidity() === false) {
+ if (node.checkValidity() === false && node.value != "") {
node.classList.add("invalid");
- node.setCustomValidity(node.title);
- node.focus();
+ //node.setCustomValidity(node.title);
+ //node.focus();
return false;
} else {
node.classList.remove("invalid");
@@ -234,22 +234,39 @@
validateInput(event.target);
});
- function onSubmit(token) {
- if (nodes.form.checkValidity() === false) {
+ nodes.form.addEventListener("submit", e => {
+ e.preventDefault();
+ e.stopPropagation();
+
+ /*if (nodes.form.checkValidity() === false) {
validateInput(nodes.uname) &&
validateInput(nodes.pwd) &&
validateInput(nodes.email);
- grecaptcha.reset();
return;
- }
+ }*/ // <= this is already being enforced by the browser
if (nodes.pwd.value.length < 12 && !window.confirm("Your password is quite short. For better security you should consider using a password at least 12 characters long.\n\nDo you really want to use a weak password?")) {
- grecaptcha.reset();
nodes.pwd.focus();
return;
}
- const req = new Request("/api/account", {
+ if (nodes.email.value.length < 3 && !window.confirm("Warning: if you do not supply an email address you will be completely unable to reset your password if you loose it.\n\nDo you really want to continue without an email address?")) {
+ nodes.email.focus();
+ return;
+ }
+
+ if (!recaptcha_loaded || !Reflect.has(window, "grecaptcha")) {
+ nodes.form.classList.add("error");
+ nodes.status.innerText = "reCAPTCHA couldn't be loaded. Make sure to whitelist this page in noscript, ghostery or any other ad/tracker blocker.";
+ nodes.status.style.display = "block"; // <= MS Edge bug
+ return;
+ }
+
+ grecaptcha.execute();
+ });
+
+ function onCaptchaCompletion(token) {
+ const req = new Request("/api/tmwa/account", {
method: "POST",
mode: "same-origin",
cache: "no-cache",
@@ -279,6 +296,8 @@
case 409:
nodes.uname.focus();
throw new Error("This username already exists!");
+ case 429:
+ throw new Error("Too many requests. Please try again later.");
case 500:
throw new Error("Internal server error. Please try again later.");
case 502:
@@ -298,10 +317,10 @@
});
}
- function Init() {
- nodes.captcha = document.querySelector(".grecaptcha-badge");
+ function ReInit() {
+ recaptcha_loaded = true;
}
</script>
- <script src="https://www.google.com/recaptcha/api.js?onload=Init" async defer></script>
+ <script src="https://www.google.com/recaptcha/api.js?onload=ReInit" async defer></script>
</body>
</html>
diff --git a/src/reset.html b/src/reset.html
new file mode 100644
index 0000000..8e334e0
--- /dev/null
+++ b/src/reset.html
@@ -0,0 +1,313 @@
+<!doctype html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
+ <title>The Mana World</title>
+ <style>
+ * {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ -webkit-font-smoothing: antialiased;
+ -moz-font-smoothing: antialiased;
+ -o-font-smoothing: antialiased;
+ font-smoothing: antialiased;
+ text-rendering: optimizeLegibility;
+ }
+
+ body {
+ font-family: "Roboto", Helvetica, Arial, sans-serif;
+ font-weight: 100;
+ font-size: 12px;
+ line-height: 30px;
+ color: #777;
+ background: #4CAF50;
+ }
+
+ .container {
+ max-width: 400px;
+ width: 100%;
+ margin: 0 auto;
+ position: relative;
+ }
+
+ .container > form input[type="text"],
+ .container > form input[type="password"],
+ .container > form input[type="email"],
+ .container > form button {
+ font: 400 12px/16px "Roboto", Helvetica, Arial, sans-serif;
+ }
+
+ .container > form {
+ background: #F9F9F9;
+ padding: 25px;
+ margin: 150px 0;
+ box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.2), 0 5px 5px 0 rgba(0, 0, 0, 0.24);
+ }
+
+ .container > form h3 {
+ display: block;
+ font-size: 30px;
+ font-weight: 300;
+ margin-bottom: 10px;
+ }
+
+ .container > form h4 {
+ margin: 5px 0 15px;
+ display: block;
+ font-size: 13px;
+ font-weight: 400;
+ }
+
+ .container .status {
+ margin: 15px 0 15px;
+ display: block;
+ font-size: 13px;
+ font-weight: 400;
+ display: none;
+ }
+
+ fieldset {
+ border: medium none !important;
+ margin: 0 0 10px;
+ min-width: 100%;
+ padding: 0;
+ width: 100%;
+ }
+
+ .container > form input[type="text"],
+ .container > form input[type="password"],
+ .container > form input[type="email"] {
+ width: 100%;
+ border: 1px solid #ccc;
+ background: #FFF;
+ margin: 0 0 5px;
+ padding: 10px;
+ }
+
+ .container > form input[type="text"]:hover,
+ .container > form input[type="password"]:hover,
+ .container > form input[type="email"]:hover {
+ -webkit-transition: border-color 0.3s ease-in-out;
+ -moz-transition: border-color 0.3s ease-in-out;
+ transition: border-color 0.3s ease-in-out;
+ border: 1px solid #aaa;
+ }
+
+ .container > form button {
+ cursor: pointer;
+ width: 100%;
+ border: none;
+ background: #4CAF50;
+ color: #FFF;
+ margin: 0 0 5px;
+ padding: 10px;
+ font-size: 15px;
+ }
+
+ .container > form button:hover {
+ background: #43A047;
+ -webkit-transition: background 0.3s ease-in-out;
+ -moz-transition: background 0.3s ease-in-out;
+ transition: background-color 0.3s ease-in-out;
+ }
+
+ .container > form button:active {
+ box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.5);
+ }
+
+ .container > form input:focus {
+ outline: 0;
+ border: 1px solid #aaa;
+ }
+
+ .grecaptcha-badge {
+ margin-bottom: 2em;
+ margin-top: 2em;
+ }
+
+ .container > form.error .status {
+ display: block!important;
+ }
+
+ input.invalid {
+ border-color: #900!important;
+ background-color: #FDD!important;
+ }
+
+ .warning {
+ color: #fff;
+ margin: 1em;
+ display: inline-block;
+ background: orangered;
+ padding: 1em;
+ border: 3px yellow dashed;
+ }
+
+ ::-webkit-input-placeholder {
+ color: #888;
+ }
+
+ :-moz-placeholder {
+ color: #888;
+ }
+
+ ::-moz-placeholder {
+ color: #888;
+ }
+
+ :-ms-input-placeholder {
+ color: #888;
+ }
+ </style>
+ <script type="text/javascript">
+ /* this block is intentionally left in <head>, for legacy browsers */
+ if (!("fetch" in window && "Request" in window && "setCustomValidity" in document.createElement("input"))) {
+ document.body.innerHTML = "<h1 style=\"color:#fff;margin:1em\">Please update your browser to continue.</h1>";
+ throw new Error("outdated browser");
+ }
+ </script>
+ </head>
+ <body>
+ <noscript>
+ <div class="warning">
+ <h1>Javascript is required for this page.</h1>
+ <!-- link to license -->
+ <!-- link to source code -->
+ </div>
+ </noscript>
+
+ <div class="container">
+ <form id="pwreset" action="#" method="POST">
+ <h3>The Mana World</h3>
+ <h4>Password reset</h4>
+ <span class="status">...</span>
+ <fieldset>
+ <input name="username" placeholder="Username" type="text" tabindex="1" minlength="4" maxlength="23" pattern="^[a-zA-Z0-9]{4,23}$" title="4-23 characters, alphanumeric" required autofocus>
+ </fieldset>
+ <fieldset>
+ <input name="email" placeholder="Email Address (optional)" type="email" maxlength="39" tabindex="3">
+ </fieldset>
+ <fieldset>
+ <div>
+ <button
+ class="g-recaptcha"
+ data-sitekey="6LdaVUcUAAAAAJ-7cORTu4cZCPSNjDqjz3y4nLVR"
+ data-callback="onSubmit"
+ data-badge="inline"
+ data-submit="...Sending"
+ type="submit">Submit</button>
+ </div>
+ </fieldset>
+ </form>
+ </div>
+ <script>
+ const nodes = {
+ uname: document.querySelector("input[name=username]"),
+ pwd: document.querySelector("input[name=password]"),
+ email: document.querySelector("input[name=email]"),
+ code: document.querySelector("input[name=code]"),
+ form: document.querySelector(".container > form"),
+ status: document.querySelector(".status"),
+ captcha: undefined
+ };
+
+ const validateInput = node => {
+ node.setCustomValidity("");
+ if (node.checkValidity() === false) {
+ node.classList.add("invalid");
+ node.setCustomValidity(node.title);
+ node.focus();
+ return false;
+ } else {
+ node.classList.remove("invalid");
+ return true;
+ }
+ };
+
+ nodes.form.addEventListener("input", event => {
+ validateInput(event.target);
+ });
+
+ function onSubmit(token) {
+ if (nodes.form.checkValidity() === false) {
+ validateInput(nodes.uname) &&
+ validateInput(nodes.pwd) &&
+ validateInput(nodes.email);
+ grecaptcha.reset();
+ return;
+ }
+
+ if (nodes.pwd.value.length < 12 && !window.confirm("Your password is quite short. For better security you should consider using a password at least 12 characters long.\n\nDo you really want to use a weak password?")) {
+ grecaptcha.reset();
+ nodes.pwd.focus();
+ return;
+ }
+
+ if (nodes.email.value.length < 3 && !window.confirm("Warning: if you do not supply an email address you will be completely unable to reset your password if you loose it.\n\nDo you really want to continue without an email address?")) {
+ grecaptcha.reset();
+ nodes.email.focus();
+ return;
+ }
+
+ const req = new Request("/api/account", {
+ method: "POST",
+ mode: "same-origin",
+ cache: "no-cache",
+ redirect: "follow",
+ referrer: "no-referrer",
+ headers: {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ "X-CAPTCHA-TOKEN": token
+ },
+ body: JSON.stringify({
+ username: nodes.uname.value,
+ password: nodes.pwd.value,
+ email: nodes.email.value,
+ }),
+ });
+
+ fetch(req)
+ .then(response => {
+ switch(response.status) {
+ case 201:
+ return response.json();
+ case 400:
+ throw new Error("Malformed request!");
+ case 403:
+ throw new Error("Failed the captcha challenge!");
+ case 409:
+ nodes.uname.focus();
+ throw new Error("This username already exists!");
+ case 429:
+ throw new Error("Too many requests. Please try again later.");
+ case 500:
+ throw new Error("Internal server error. Please try again later.");
+ case 502:
+ throw new Error("Couldn't reach the server. Please try again later.");
+ default:
+ throw new Error(`Received status code ${response.status}.`);
+ }
+ })
+ .then(response => {
+ nodes.form.innerText = "Account created successfully.\nIt may take a few minutes before you are able to log in.";
+ })
+ .catch(error => {
+ nodes.form.classList.add("error");
+ nodes.status.innerText = error;
+ nodes.status.style.display = "block"; // <= MS Edge bug
+ grecaptcha.reset();
+ });
+ }
+
+ function Init() {
+ nodes.captcha = document.querySelector(".grecaptcha-badge");
+ }
+ </script>
+ <script src="https://www.google.com/recaptcha/api.js?onload=Init" async defer></script>
+ </body>
+</html>