Make accounts frontend!
This commit is contained in:
34
index.html
34
index.html
@@ -7,6 +7,12 @@
|
|||||||
name="viewport"
|
name="viewport"
|
||||||
content="initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no"
|
content="initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no"
|
||||||
/>
|
/>
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
|
<link
|
||||||
|
href="https://fonts.googleapis.com/css2?family=WDXL+Lubrifont+JP+N&display=swap"
|
||||||
|
rel="stylesheet"
|
||||||
|
/>
|
||||||
<link rel="stylesheet" href="src/assets/style.css" />
|
<link rel="stylesheet" href="src/assets/style.css" />
|
||||||
<script type="module" src="src/js/accounts.js"></script>
|
<script type="module" src="src/js/accounts.js"></script>
|
||||||
</head>
|
</head>
|
||||||
@@ -22,37 +28,46 @@
|
|||||||
<div class="header-right">
|
<div class="header-right">
|
||||||
<button class="account-button" id="login-button">LOGIN</button>
|
<button class="account-button" id="login-button">LOGIN</button>
|
||||||
<button class="account-button" id="signup-button">SIGN UP</button>
|
<button class="account-button" id="signup-button">SIGN UP</button>
|
||||||
|
<button class="account-button" id="logout-button">LOGOUT</button>
|
||||||
|
<button class="account-button" id="forgot-button">
|
||||||
|
FORGOT - DEBUG
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<canvas id="main-canvas"></canvas>
|
<canvas id="main-canvas"></canvas>
|
||||||
<script type="module" src="src/js/game.js"></script>
|
<script type="module" src="src/js/game.js"></script>
|
||||||
<div class="popup">
|
<div class="popup" id="popup">
|
||||||
|
<span class="close" id="close">×</span>
|
||||||
<div class="popup-tab" id="login">
|
<div class="popup-tab" id="login">
|
||||||
<span class="info" id="login-info"></span>
|
|
||||||
<form id="login-form" class="form">
|
<form id="login-form" class="form">
|
||||||
|
<label for="username">USERNAME</label>
|
||||||
<input type="text" name="username" placeholder="Username" required />
|
<input type="text" name="username" placeholder="Username" required />
|
||||||
|
<label for="pass">PASSWORD</label>
|
||||||
<input type="password" name="pass" placeholder="Password" required />
|
<input type="password" name="pass" placeholder="Password" required />
|
||||||
<button type="submit">Login</button>
|
<button type="submit">LOGIN</button>
|
||||||
|
<span class="info" id="login-info"></span>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="popup-tab" id="signup">
|
<div class="popup-tab" id="signup">
|
||||||
<form id="signup-form" class="form">
|
<form id="signup-form" class="form">
|
||||||
<span class="info" id="signup-info"></span>
|
<label for="username">USERNAME</label>
|
||||||
<input type="text" name="username" placeholder="Username" required />
|
<input type="text" name="username" placeholder="Username" required />
|
||||||
|
<label for="email">EMAIL</label>
|
||||||
<input type="email" name="email" placeholder="Email" required />
|
<input type="email" name="email" placeholder="Email" required />
|
||||||
|
<label for="pass">PASSWORD</label>
|
||||||
<input type="password" name="pass" placeholder="Password" required />
|
<input type="password" name="pass" placeholder="Password" required />
|
||||||
<button type="submit">Sign Up</button>
|
<button type="submit">SIGN UP</button>
|
||||||
|
<span class="info" id="signup-info"></span>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="popup-tab" id="forgot-pass">
|
<div class="popup-tab" id="forgot-pass">
|
||||||
<span class="info" id="forgot-info"></span>
|
|
||||||
<form id="forgot-form" class="form">
|
<form id="forgot-form" class="form">
|
||||||
<input type="email" name="email" placeholder="Email" />
|
<input type="email" name="email" placeholder="Email" />
|
||||||
<button type="submit">Submit</button>
|
<button type="submit">SUBMIT</button>
|
||||||
|
<span class="info" id="forgot-info"></span>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="popup-tab" id="reset-pass">
|
<div class="popup-tab" id="reset-pass">
|
||||||
<span class="info" id="reset-info"></span>
|
|
||||||
<form id="reset-form" class="form">
|
<form id="reset-form" class="form">
|
||||||
<input type="password" name="pass" placeholder="Password" required />
|
<input type="password" name="pass" placeholder="Password" required />
|
||||||
<input
|
<input
|
||||||
@@ -61,7 +76,8 @@
|
|||||||
placeholder="Confirm Password"
|
placeholder="Confirm Password"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
<button type="submit">Submit</button>
|
<button type="submit">SUBMIT</button>
|
||||||
|
<span class="info" id="reset-info"></span>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
21
main.rb
21
main.rb
@@ -115,9 +115,28 @@ post "/forgot_password" do
|
|||||||
status 400
|
status 400
|
||||||
return { "message" => "Bad request made (Email not provided)!" }.to_json
|
return { "message" => "Bad request made (Email not provided)!" }.to_json
|
||||||
end
|
end
|
||||||
Players.pass_req(data["email"])
|
if Players.pass_req(data["email"])
|
||||||
status 200
|
status 200
|
||||||
return { "message" => "Email sent successfully!" }.to_json
|
return { "message" => "Email sent successfully!" }.to_json
|
||||||
|
else
|
||||||
|
status 400
|
||||||
|
return { "message" => "Couldn't send email!" }.to_json
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
post "/pass_reset?" do
|
||||||
|
data = JSON.parse(request.body.read)
|
||||||
|
if data["code"].nil?
|
||||||
|
status 400
|
||||||
|
return { "message" => "Bad request made!" }.to_json
|
||||||
|
end
|
||||||
|
if Players.pass_reset?(data["code"])
|
||||||
|
status 200
|
||||||
|
return { "message" => "Password reset link exists!" }.to_json
|
||||||
|
else
|
||||||
|
status 400
|
||||||
|
return { "message" => "Code doesn't exist!" }.to_json
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
get "/reset_password/:code" do
|
get "/reset_password/:code" do
|
||||||
|
16
players.rb
16
players.rb
@@ -41,12 +41,16 @@ module Players
|
|||||||
end
|
end
|
||||||
|
|
||||||
def self.pass_req(email)
|
def self.pass_req(email)
|
||||||
return unless self[email]
|
return false unless by_email(email)
|
||||||
|
|
||||||
code = Array.new(24) { ALPHANUM.sample }.join
|
code = Array.new(24) { ALPHANUM.sample }.join
|
||||||
DB["update Players set new_pass_code = ? where email = ?", code, email].update
|
DB["update Players set new_pass_code = ? where email = ?", code, email].update
|
||||||
|
|
||||||
send_email(:pass_req, email, code)
|
Logman.log "Pass req: #{email} & #{code}\n"
|
||||||
|
|
||||||
|
true
|
||||||
|
|
||||||
|
# send_email(:pass_req, email, code)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.pass_reset(new_pass, code)
|
def self.pass_reset(new_pass, code)
|
||||||
@@ -54,10 +58,18 @@ module Players
|
|||||||
DB["update Players set digest = ?, new_pass_code = ? where new_pass_code = ?", digest, "", code].update != 0
|
DB["update Players set digest = ?, new_pass_code = ? where new_pass_code = ?", digest, "", code].update != 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.pass_reset?(code)
|
||||||
|
DB["select * from Players where new_pass_code = ?", code].first
|
||||||
|
end
|
||||||
|
|
||||||
def self.[](username)
|
def self.[](username)
|
||||||
DB["select * from Players where username = ?", username].first
|
DB["select * from Players where username = ?", username].first
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.by_email(email)
|
||||||
|
DB["select * from Players where email = ?", email].first
|
||||||
|
end
|
||||||
|
|
||||||
def self.[]=(username, data)
|
def self.[]=(username, data)
|
||||||
DB["update Players set data = ? where username = ?", data, username].update
|
DB["update Players set data = ? where username = ?", data, username].update
|
||||||
end
|
end
|
||||||
|
Binary file not shown.
@@ -1,15 +1,10 @@
|
|||||||
|
@import url("https://fonts.googleapis.com/css2?family=WDXL+Lubrifont+JP+N&display=swap");
|
||||||
|
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "Changa";
|
|
||||||
src: url("fonts/changa.woff") format("opentype");
|
|
||||||
font-weight: normal;
|
|
||||||
font-style: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 90px;
|
height: 90px;
|
||||||
@@ -18,7 +13,12 @@ body {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
font-family: "Changa";
|
font-family: "WDXL Lubrifont JP N", sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
font-family: "WDXL Lubrifont JP N", sans-serif;
|
||||||
|
font-size: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.logo {
|
.logo {
|
||||||
@@ -32,17 +32,100 @@ body {
|
|||||||
top: 50%;
|
top: 50%;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
width: 500px;
|
width: 400px;
|
||||||
height: 500px;
|
padding-top: 20px;
|
||||||
background-color: rgba(0, 0, 0, 0.5);
|
background-color: #1b262c70;
|
||||||
display: flex;
|
backdrop-filter: blur(8px);
|
||||||
|
display: none;
|
||||||
|
border-radius: 30px;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
z-index: 9999;
|
z-index: 9999;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.close {
|
||||||
|
position: absolute;
|
||||||
|
top: 5px;
|
||||||
|
right: 15px;
|
||||||
|
font-size: 24px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 29px;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close:hover {
|
||||||
|
color: #fa908c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup.active {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
.popup-tab {
|
.popup-tab {
|
||||||
display: none;
|
display: none;
|
||||||
|
width: calc(100% - 60px);
|
||||||
|
height: calc(100% - 60px);
|
||||||
|
padding: 20px 30px;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
color: red;
|
||||||
|
font-weight: bold;
|
||||||
|
opacity: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info:empty::before {
|
||||||
|
content: "\00a0";
|
||||||
|
visibility: hidden;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info.active {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form input {
|
||||||
|
padding: 10px;
|
||||||
|
width: 80%;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form label {
|
||||||
|
font-size: 16px;
|
||||||
|
font-family: "WDXL Lubrifont JP N", sans-serif;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form button {
|
||||||
|
margin-top: 20px;
|
||||||
|
padding: 10px;
|
||||||
|
background-color: #3498db;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
width: 25%;
|
||||||
|
border-radius: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form button:hover {
|
||||||
|
background-color: #2980b9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-tab.active {
|
||||||
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-right {
|
.header-right {
|
||||||
|
@@ -1,14 +1,60 @@
|
|||||||
|
window.onload = async () => {
|
||||||
const login_form = document.getElementById("login-form");
|
const login_form = document.getElementById("login-form");
|
||||||
const login_button = document.getElementById("login-button");
|
const login_button = document.getElementById("login-button");
|
||||||
const signup_form = document.getElementById("signup-form");
|
const signup_form = document.getElementById("signup-form");
|
||||||
const signup_button = document.getElementById("signup-button");
|
const signup_button = document.getElementById("signup-button");
|
||||||
|
const logout_button = document.getElementById("logout-button");
|
||||||
|
const forgot_button = document.getElementById("forgot-button");
|
||||||
|
const forgot_form = document.getElementById("forgot-form");
|
||||||
|
|
||||||
|
forgot_button.onclick = () => {
|
||||||
|
document.getElementById("popup").classList.add("active");
|
||||||
|
document.getElementById("forgot-pass").classList.add("active");
|
||||||
|
document.getElementById("login").classList.remove("active");
|
||||||
|
document.getElementById("signup").classList.remove("active");
|
||||||
|
document.getElementById("reset-pass").classList.remove("active");
|
||||||
|
};
|
||||||
|
|
||||||
|
forgot_form.onsubmit = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const email = forgot_form.email.value;
|
||||||
|
const res = await fetch("/forgot_password", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ email }),
|
||||||
|
});
|
||||||
|
const data = await res.json();
|
||||||
|
document.getElementById("forgot-info").innerHTML = data.message;
|
||||||
|
};
|
||||||
|
|
||||||
|
logout_button.onclick = () => {
|
||||||
|
window.location.href = "/logout";
|
||||||
|
};
|
||||||
|
|
||||||
login_button.onclick = () => {
|
login_button.onclick = () => {
|
||||||
document.getElementById("login").style.display = "block";
|
document.getElementById("popup").classList.add("active");
|
||||||
|
document.getElementById("login").classList.add("active");
|
||||||
|
document.getElementById("signup").classList.remove("active");
|
||||||
|
document.getElementById("forgot-pass").classList.remove("active");
|
||||||
|
document.getElementById("reset-pass").classList.remove("active");
|
||||||
};
|
};
|
||||||
|
|
||||||
signup_button.onclick = () => {
|
signup_button.onclick = () => {
|
||||||
document.getElementById("signup").style.display = "block";
|
document.getElementById("popup").classList.add("active");
|
||||||
|
document.getElementById("signup").classList.add("active");
|
||||||
|
document.getElementById("login").classList.remove("active");
|
||||||
|
document.getElementById("forgot-pass").classList.remove("active");
|
||||||
|
document.getElementById("reset-pass").classList.remove("active");
|
||||||
|
};
|
||||||
|
|
||||||
|
document.getElementById("close").onclick = () => {
|
||||||
|
document.getElementById("popup").classList.remove("active");
|
||||||
|
document.getElementById("login").classList.remove("active");
|
||||||
|
document.getElementById("signup").classList.remove("active");
|
||||||
|
document.getElementById("forgot-pass").classList.remove("active");
|
||||||
|
document.getElementById("reset-pass").classList.remove("active");
|
||||||
};
|
};
|
||||||
|
|
||||||
login_form.onsubmit = async (e) => {
|
login_form.onsubmit = async (e) => {
|
||||||
@@ -41,3 +87,46 @@ signup_form.onsubmit = async (e) => {
|
|||||||
response = await response.json();
|
response = await response.json();
|
||||||
document.getElementById("signup-info").innerText = response.message;
|
document.getElementById("signup-info").innerText = response.message;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const params = new URLSearchParams(window.location.search);
|
||||||
|
const reset_code = params.get("reset_code");
|
||||||
|
if (reset_code) {
|
||||||
|
let response = await fetch("/pass_reset?", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ code: reset_code }),
|
||||||
|
});
|
||||||
|
let status = response.status;
|
||||||
|
if (status == 200) {
|
||||||
|
document.getElementById("popup").classList.add("active");
|
||||||
|
document.getElementById("reset-pass").classList.add("active");
|
||||||
|
document.getElementById("login").classList.remove("active");
|
||||||
|
document.getElementById("signup").classList.remove("active");
|
||||||
|
document.getElementById("forgot-pass").classList.remove("active");
|
||||||
|
document.getElementById("reset-form").onsubmit = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const pass = document.getElementById("reset-form").pass.value;
|
||||||
|
const pass_confirm =
|
||||||
|
document.getElementById("reset-form").pass_confirm.value;
|
||||||
|
if (pass != pass_confirm) {
|
||||||
|
document.getElementById("reset-info").innerText =
|
||||||
|
"Passwords do not match";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let response = await fetch("/reset_password/" + reset_code, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ pass }),
|
||||||
|
});
|
||||||
|
response = await response.json();
|
||||||
|
document.getElementById("reset-info").innerText = response.message;
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
window.location.href = "/";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
@@ -98,6 +98,8 @@ class Sessions
|
|||||||
session = session.nil? ? "{}" : Zlib::Inflate.inflate(Base64.decode64(session))
|
session = session.nil? ? "{}" : Zlib::Inflate.inflate(Base64.decode64(session))
|
||||||
session = JSON.parse(session)
|
session = JSON.parse(session)
|
||||||
session.delete(key)
|
session.delete(key)
|
||||||
|
Logman.log "Deleted: #{key}"
|
||||||
|
Logman.log session.inspect
|
||||||
compressed = Zlib::Deflate.deflate(JSON.generate(session))
|
compressed = Zlib::Deflate.deflate(JSON.generate(session))
|
||||||
encoded = Base64.encode64(compressed)
|
encoded = Base64.encode64(compressed)
|
||||||
@response.set_cookie("session",
|
@response.set_cookie("session",
|
||||||
|
Reference in New Issue
Block a user