aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore4
-rw-r--r--README.md4
-rw-r--r--index.js63
-rw-r--r--package.json7
-rw-r--r--public/css/style.css17
-rw-r--r--status.json37
-rw-r--r--views/dashboard.ejs42
-rw-r--r--views/error.ejs4
-rw-r--r--views/index.ejs6
-rw-r--r--views/password.ejs22
-rw-r--r--views/register.ejs5
-rw-r--r--views/success.ejs7
12 files changed, 160 insertions, 58 deletions
diff --git a/.gitignore b/.gitignore
index d00f5cc..a51afe2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -174,4 +174,6 @@ dist
# Finder (MacOS) folder config
.DS_Store
-*.db \ No newline at end of file
+*.db
+
+.idea/ \ No newline at end of file
diff --git a/README.md b/README.md
index a092fcf..bb32808 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
# bnbso-auth
-Web authentication for bnbSO (registering accounts, resetting passwords, changing passwords) using Discord authentication. Designed for FreeSO-based servers.
+Web authentication for bnbSO (registering accounts, changing passwords) using Discord authentication. Designed for FreeSO-based servers.
To install dependencies:
@@ -10,7 +10,7 @@ bun install
To run:
```bash
-bun run index.ts
+bun run index.js
```
This project was created using `bun init` in bun v1.1.38. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime.
diff --git a/index.js b/index.js
index 1e03b94..d1744d4 100644
--- a/index.js
+++ b/index.js
@@ -86,7 +86,7 @@ app.get("/", async (req, res) => {
}
});
} else {
- return res.render('error', { error: 'You must be a member of the bits & Bytes server to access this page.' });
+ return res.render('error', { error: 'You must be a member of that server to access this page.' });
}
} else {
res.render('index');
@@ -105,7 +105,7 @@ app.post("/register", upload.none(), async (req, res) => {
try {
const form = new FormData();
form.append('username', username);
- form.append('email', id + '@discord.com');
+ form.append('email', `${id}@discord.com`);
form.append('password', password);
form.append('key', process.env.REG_KEY);
@@ -123,7 +123,7 @@ app.post("/register", upload.none(), async (req, res) => {
console.error("Error inserting user data into database:", err);
return res.render('register', { ...req.user, error: "An error occurred during registration, contact server operator." });
}
- return res.render('success');
+ return res.render('success', { ...req.user, success: "Created account successfully!"});
});
}
} catch (error) {
@@ -131,7 +131,62 @@ app.post("/register", upload.none(), async (req, res) => {
return res.render('register', { ...req.user, error: "An error occurred during registration, contact server operator." });
}
} else {
- res.redirect("/");
+ res.status(401).send("Unauthorized.");
+ }
+});
+
+app.get('/password', (req, res) => {
+ if (req.isAuthenticated()) {
+ res.render('password');
+ } else {
+ res.redirect("/auth/discord");
+ }
+});
+
+app.post('/password/change', upload.none(), async (req, res) => {
+ if (req.isAuthenticated()) {
+ const { id } = req.user;
+ const { currentpassword, newpassword, newpassword2 } = req.body;
+
+ if (newpassword !== newpassword2) {
+ return res.render('password', { ...req.user, error: "Passwords do not match" });
+ }
+
+ try {
+ db.get(`SELECT * FROM users WHERE discord_id = ?`, [id], async (err, row) => {
+ if (err) {
+ console.error("Error querying the database:", err);
+ return res.render('password', {...req.user, error: "An error occurred while checking user data."});
+ }
+
+ if (row) {
+ const form = new FormData();
+ form.append('username', row.fso_username);
+ form.append('old_password', currentpassword);
+ form.append('new_password', newpassword);
+
+ const response = await axios.post(`${process.env.API_URL}/userapi/password`, form, {
+ headers: form.getHeaders()
+ });
+
+ if (response.data.error) {
+ const errorKey = response.data.error_description || "default";
+ const errorMessage = statusMessages.password_reset_errors[errorKey] || "Something went wrong";
+
+ return res.render('password', { ...req.user, error: errorMessage });
+ }
+
+ return res.render('success', { ...req.user, success: "Password changed successfully!" });
+ }
+ });
+
+ } catch (error) {
+ console.error("Error during password change:", error);
+ return res.render('password', { ...req.user, error: "An error occurred during password change, contact server operator." });
+ }
+
+ } else {
+ res.status(401).send("Unauthorized.");
}
});
diff --git a/package.json b/package.json
index 10776ca..ed9fd67 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,10 @@
{
"name": "bnbso-auth",
- "module": "index.ts",
+ "module": "index.js",
"type": "module",
+ "scripts": {
+ "start": "node index.js"
+ },
"devDependencies": {
"@types/bun": "latest"
},
@@ -20,4 +23,4 @@
"passport-discord": "^0.1.4",
"sqlite3": "^5.1.7"
}
-} \ No newline at end of file
+}
diff --git a/public/css/style.css b/public/css/style.css
index a6c3ea8..1472a8c 100644
--- a/public/css/style.css
+++ b/public/css/style.css
@@ -1,10 +1,10 @@
@import url('https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300..800;1,300..800&display=swap');
-
+
html, body {
height: 100%;
margin: 0;
padding: 0;
-}
+}
body {
display: flex;
@@ -34,7 +34,7 @@ a:active {
display: inline-block;
text-decoration: none;
color: #fff;
- background-color: #00633a;
+ background-color: #535353;
padding: 10px 20px;
border-radius: 5px;
transition: 0.2s;
@@ -43,12 +43,12 @@ a:active {
}
.button:hover {
- background-color: #009959;
+ background-color: #8a8a8a;
color: #fff;
}
.button:active {
- background-color: #003620;
+ background-color: #454545;
color: #fff;
}
@@ -139,4 +139,9 @@ button {
.error {
color: #f88c8c;
font-size: 1.5em;
-} \ No newline at end of file
+}
+
+.success {
+ color: #a3f88c;
+ font-size: 1.5em;
+}
diff --git a/status.json b/status.json
index eb1f9e9..076dd3a 100644
--- a/status.json
+++ b/status.json
@@ -1,29 +1,28 @@
{
"registration_errors": {
- "missing_confirmation_token": "Registration failed: Missing confirmation token.",
- "user_short": "Registration failed: Username is too short.",
- "user_long": "Registration failed: Username is too long.",
- "user_invalid": "Registration failed: Invalid username.",
- "pass_required": "Registration failed: Password is required.",
- "email_invalid": "Registration failed: Invalid email address.",
- "ip_banned": "Registration failed: IP is banned.",
- "registrations_too_frequent": "Registration failed: Too many registrations from this IP address.",
- "user_exists": "Registration failed: User already exists.",
- "smtp_disabled": "Registration failed: SMTP service is disabled.",
- "email_taken": "Registration failed: Email address is already taken.",
- "confirmation_pending": "Registration failed: Confirmation pending.",
- "key_wrong": "Registration failed: Invalid registration key."
+ "missing_confirmation_token": "Missing confirmation token.",
+ "user_short": "Username is too short.",
+ "user_long": "Username is too long.",
+ "user_invalid": "Invalid username.",
+ "pass_required": "Password is required.",
+ "email_invalid": "Invalid email address.",
+ "ip_banned": "IP is banned.",
+ "registrations_too_frequent": "Too many registrations from this IP address.",
+ "user_exists": "User already exists.",
+ "smtp_disabled": "SMTP service is disabled.",
+ "email_taken": "Email address is already taken.",
+ "confirmation_pending": "Confirmation pending.",
+ "key_wrong": "Invalid registration key."
},
"password_reset_errors": {
- "missing_fields": "Password reset failed: Missing required fields.",
- "email_invalid": "Password reset failed: Invalid email address.",
- "user_invalid": "Password reset failed: User does not exist.",
- "incorrect_password": "Password reset failed: Incorrect password.",
- "invalid_token": "Password reset failed: Invalid confirmation token."
+ "missing_fields": "Missing required fields.",
+ "email_invalid": "Invalid email address.",
+ "user_invalid": "User does not exist.",
+ "incorrect_password": "Incorrect password.",
+ "invalid_token": "Invalid confirmation token."
},
"success_responses": {
"success": "Operation was successful.",
"email_failed": "Email sending failed."
}
}
- \ No newline at end of file
diff --git a/views/dashboard.ejs b/views/dashboard.ejs
index 1c7996b..b7c82d5 100644
--- a/views/dashboard.ejs
+++ b/views/dashboard.ejs
@@ -9,12 +9,44 @@
<body>
<div class="background"></div>
<div class="container">
- <img src="img/logo.png" alt="logo" width="200">
+ <img src="/img/logo.png" alt="logo" width="200">
<h1>Welcome, <%= username %>!</h1>
- <h2>FreeSO Username: <%= fso_username %></h2>
- <a href="#" class="button">Change Password</a>
- <a href="#" class="button">Download bnbSO Client</a>
+ <h2>bnbSO Username: <%= fso_username %></h2>
+ <h2 id="simtime"></h2>
+ <a href="/password" class="button">Change Password</a>
+ <a href="https://fso-builds.riperiperi.workers.dev" class="button">Download bnbSO Client</a>
<a href="/logout" class="button logout">Logout</a>
</div>
+ <script>
+ function updateTSOClock() {
+ const currentTime = new Date(),
+ utcMinutes = currentTime.getUTCMinutes(),
+ utcSeconds = currentTime.getUTCSeconds();
+ let timePeriod = 'AM', totalSeconds = 0;
+ if (currentTime.getUTCHours() % 2 === 1) {
+ totalSeconds = 3600;
+ timePeriod = 'PM';
+ }
+ totalSeconds += utcMinutes * 60 + utcSeconds;
+ let hour = Math.floor(totalSeconds / 300);
+ if (hour > 12) {
+ hour -= 12;
+ }
+ if (hour === 0) {
+ hour = 12;
+ }
+ let minute = Math.floor(totalSeconds % 300 / 5);
+ if (minute < 10) {
+ minute = '0' + minute;
+ }
+ const simTimeElement = document.querySelector('#simtime');
+ if (simTimeElement) {
+ simTimeElement.textContent = `${hour}:${minute} ${timePeriod}`;
+ }
+ }
+
+ setInterval(updateTSOClock, 1000);
+ updateTSOClock();
+ </script>
</body>
-</html> \ No newline at end of file
+</html>
diff --git a/views/error.ejs b/views/error.ejs
index dc138e6..b867d30 100644
--- a/views/error.ejs
+++ b/views/error.ejs
@@ -9,9 +9,9 @@
<body>
<div class="background"></div>
<div class="container">
- <img src="img/logo.png" alt="logo" width="200">
+ <img src="/img/logo.png" alt="logo" width="200">
<h1>Oh no! Something went wrong!</h1>
<p><%= error %></p>
</div>
</body>
-</html> \ No newline at end of file
+</html>
diff --git a/views/index.ejs b/views/index.ejs
index e786bd3..7a9b8a4 100644
--- a/views/index.ejs
+++ b/views/index.ejs
@@ -9,10 +9,10 @@
<body>
<div class="background"></div>
<div class="container">
- <img src="img/logo.png" alt="logo" width="200">
+ <img src="/img/logo.png" alt="logo" width="200">
<p>Log into your Discord account to get access to bnbSO.</p>
<p><i>You must be a bits & Bytes member.</i></p>
- <a class="button discord" href="/auth/discord">Login with Discord</a>
+ <a class="button discord" href="/auth/discord">Login with Discord</a>
</div>
</body>
-</html> \ No newline at end of file
+</html>
diff --git a/views/password.ejs b/views/password.ejs
index f66b60b..8033aae 100644
--- a/views/password.ejs
+++ b/views/password.ejs
@@ -9,18 +9,22 @@
<body>
<div class="background"></div>
<div class="container">
- <img src="img/logo.png" alt="logo" width="200">
+ <img src="/img/logo.png" alt="logo" width="200">
<h1>Change Password</h1>
- <p>If you have issues changing your password, ask the server operator to change your password.</p>
- <form method="post" action="/login">
- <label for="username">Username:</label>
- <input type="text" id="username" name="username">
- <label for="password">Current Password:</label>
- <input type="password" id="password" name="password">
- <button type="submit">Login</button>
+ <p>If you have issues changing your password, ask the server operator to reset your password.</p>
+ <form method="post" action="/password/change">
+ <label for="currentpassword">Current Password:</label>
+ <input type="password" id="currentpassword" name="currentpassword">
+ <label for="newpassword">New Password:</label>
+ <input type="password" id="newpassword" name="newpassword">
+ <label for="newpassword2">Confirm New Password:</label>
+ <input type="password" id="newpassword2" name="newpassword2">
+ <button type="submit">Change Password</button>
</form>
+ <a href="/" class="button">Dashboard</a>
<% if (typeof error !== 'undefined') { %>
<div class="error"><%= error %></div>
<% } %>
+ </div>
</body>
-</html> \ No newline at end of file
+</html>
diff --git a/views/register.ejs b/views/register.ejs
index f417f82..d54013d 100644
--- a/views/register.ejs
+++ b/views/register.ejs
@@ -9,7 +9,7 @@
<body>
<div class="background"></div>
<div class="container">
- <img src="img/logo.png" alt="logo" width="200">
+ <img src="/img/logo.png" alt="logo" width="200">
<h1>Welcome to bnbSO!</h1>
<p>You will be sending the following information to register your bnbSO account</p>
<p>Please verify that the following information is correct. You can only change your username <b>once</b>.</p>
@@ -25,5 +25,6 @@
<% if (typeof error !== 'undefined') { %>
<div class="error"><%= error %></div>
<% } %>
+ </div>
</body>
-</html> \ No newline at end of file
+</html>
diff --git a/views/success.ejs b/views/success.ejs
index 2ec9771..f87ea2f 100644
--- a/views/success.ejs
+++ b/views/success.ejs
@@ -9,9 +9,10 @@
<body>
<div class="background"></div>
<div class="container">
- <img src="img/logo.png" alt="logo" width="200">
- <p>Created account successfully!</p>
+ <img src="/img/logo.png" alt="logo" width="200">
+ <h1>Success!</h1>
+ <p class="success"><%= success %></p>
<a href="/">Dashboard</a>
</div>
</body>
-</html> \ No newline at end of file
+</html>