-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
206 lines (181 loc) · 5.74 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
import express from "express";
import mc from "minecraftstatuspinger";
import crypto from "crypto";
import nodemailer from "nodemailer";
import mariadb from "mariadb";
import "dotenv/config";
const port = process.env.PORT || 3000;
const dbName = process.env.DB_NAME || "mc_stats";
const pool = mariadb.createPool({
host: process.env.DB_HOST,
user: process.env.DB_USER,
database: dbName,
password: process.env.DB_PASS,
connectionLimit: 5,
});
// seed db
const seed = async () => {
let conn;
try {
conn = await pool.getConnection();
await conn.query(`CREATE DATABASE IF NOT EXISTS ${dbName}`);
await conn.query(`USE ${dbName}`);
await conn.query(
`CREATE TABLE IF NOT EXISTS users (id INT AUTO_INCREMENT PRIMARY KEY, email VARCHAR(255), username VARCHAR(255), uuid VARCHAR(255), active BOOLEAN)`
);
await conn.query(
`CREATE TABLE IF NOT EXISTS confirmations (id INT AUTO_INCREMENT PRIMARY KEY, user_id INT, token VARCHAR(255))`
);
console.log("Database initialized");
} catch (err) {
console.error(err);
console.log("Retrying in 30 seconds");
setTimeout(seed, 30000);
} finally {
if (conn) conn.end();
}
};
seed();
const app = express();
app.use(express.static("../frontend/dist")); // use public
app.use(express.json()); // to support JSON-encoded bodies
app.use(express.urlencoded({ extended: true })); // to support URL-encoded bodies
const transporter = nodemailer.createTransport({
host: process.env.MAIL_HOST,
port: process.env.MAIL_PORT,
secure: process.env.MAIL_SSL === "true" ? true : false,
auth: {
user: process.env.MAIL_USER,
pass: process.env.MAIL_PASS,
},
});
app.post("/register", async (req, res) => {
let userEmail = req.body.email.toLowerCase();
if (!userEmail.endsWith("@chalmers.se")) {
res.status(400).send("Invalid email");
return;
}
let username = req.body.username.toLowerCase();
// check that username is only letters and numbers or underscore
if (!/^[a-z0-9_]+$/.test(username)) {
res.status(400).send("Invalid username");
return;
}
// check that username is under 64 characters
if (username.length > 16) {
res.status(400).send("Username is too long");
return;
}
let response = await fetch(
`https://api.mojang.com/users/profiles/minecraft/${username}`
);
if (response.status === 404) {
res.status(400).send("Username doesn't exist");
return;
}
let uuid = await response.json().id;
let token = crypto.randomBytes(32).toString("hex");
let conn;
try {
conn = await pool.getConnection();
// Check if email already exists
let sql = "SELECT * FROM users WHERE email = ?";
let rows = await conn.query(sql, [userEmail]);
if (rows.length > 0) {
res
.status(400)
.send(
"Email already in use, search your inbox for a confirmation email or contact an admin for assistance"
);
return;
}
sql =
"INSERT INTO users (email, username, uuid, active) VALUES (?, ?, ?, 0)";
await conn.query(sql, [userEmail, username, uuid]);
sql = "SELECT id FROM users WHERE email = ?";
rows = await conn.query(sql, [userEmail]);
let userId = rows[0].id;
sql = "INSERT INTO confirmations (user_id, token) VALUES (?, ?)";
await conn.query(sql, [userId, token]);
} catch (err) {
console.error(err);
} finally {
if (conn) conn.end();
}
// Send email with the token
let mailOptions = {
from: `"${process.env.MAIL_NAME}" <${process.env.MAIL_FROM}>`,
to: userEmail,
subject: "Registration Confirmation for mc.chs.se",
text: `Please confirm your registration by clicking the following link:
<a href='http://${req.headers.host}/confirm/${token}'>http://${req.headers.host}/confirm/${token}</a>
If you did not request this, please ignore this email.`,
};
transporter.sendMail(mailOptions, function (err) {
if (err) {
console.error("There was an error: ", err);
} else {
console.log("Email sent");
}
});
res.send("Check your email for a confirmation link");
});
app.get("/confirm/:token", async (req, res) => {
let token = req.params.token;
let conn;
try {
conn = await pool.getConnection();
let sql = "SELECT user_id FROM confirmations WHERE token = ?";
const rows = await conn.query(sql, [token]);
if (rows.length) {
// If the token exists, delete it from the database and set the user to active
sql = "DELETE FROM confirmations WHERE token = ?";
await conn.query(sql, [token]);
sql = "UPDATE users SET active = 1 WHERE id = ?";
await conn.query(sql, [rows[0].user_id]);
res.send(`Your account has been activated. Redirecting to the home page...
<script>
setTimeout(() => {
window.location.href = '/';
}, 3000);
</script>`);
} else {
res.send("Invalid token. Try again. <a href='/'>Go to back</a>");
}
} catch (err) {
console.error(err);
} finally {
if (conn) conn.end();
}
});
app.get("/ping", async (_, res) => {
try {
let result = await mc.lookup({ host: "mc.chs.se" });
res.send(result);
} catch (error) {
//server is offline
res.send({ error: "Server is offline" });
}
});
app.post("/check", async (req, res) => {
let uuid = req.body.uuid;
let conn;
try {
conn = await pool.getConnection();
let sql = "SELECT * FROM users WHERE uuid = ?";
let rows = await conn.query(sql, [uuid]);
if (rows.length > 0) {
res.send({ status: rows[0].active ? "success" : "denied" });
} else {
res.send({ status: "denied" });
}
} catch (err) {
console.error(err);
res.send({ status: "denied" });
} finally {
if (conn) conn.end();
}
});
app.listen(port, () => {
console.log(`App listening at http://localhost:${port}`);
});