import { env, exit } from "process"; // import * as fs from "fs"; import { randomBytes, pbkdf2Sync } from "crypto"; import * as assert from "assert"; import * as express from "express"; import * as cors from "cors"; import * as bodyparser from "body-parser"; //@ts-ignore //import * as Filter from "bad-words"; import { isAuthenticated, performLogin } from "./security/auth"; import { LRequest } from "./types/express"; import UserRouter from "./api/user"; import ClassRouter from "./api/class"; import LevelRouter from "./api/level"; const baseRouter = express.Router(); const authRouter = express.Router(); import { MongoClient } from "mongodb"; const user = encodeURIComponent("backend"); const password = encodeURIComponent(env["LATEINICUS_USER_PW"]); (async function() { // Load the profanity list // const list = JSON.parse(fs.readFileSync("/etc/profanity", { encoding: "utf-8" })); // const profanityFilter = new Filter({ // list, // }); // Database Name const dbName = 'lateinicus'; // Connection URL const url = `mongodb://${user}:${password}@128.1.0.2:27017/?authMechanism=SCRAM-SHA-1&authSource=${dbName}`; let client: MongoClient; try { // Use connect method to connect to the Server client = await MongoClient.connect(url); console.log("Connected to MongoDB"); } catch (err) { console.log(err.stack); assert(false); } const db = client.db(dbName); console.log("Connected to the database"); const app = express(); app.use(bodyparser.json()); app.options("*", cors()); app.use((req: LRequest, res, next) => { // Every route should have access to the database so that // we can easily make calls to it req.db = db; next(); }); app.use("/api/level", LevelRouter); app.use("/api/class", ClassRouter); app.use("/api/user", UserRouter); app.get("/api/levels", async (req, res) => { // TODO: if (levels) const levels = (await db.collection("levels").find({}, { // The order in which we send the levels is important, so better // sort them sort: { level: 1, }, }) .toArray()) .map((el) => { let tmp = Object.assign({}, el); delete tmp.vocab; delete tmp._id; return tmp; }); res.send({ error: "0", data: { levels, }, }); }); app.post("/api/register", async (req, res) => { // Check if any data was sent if (!req.body) { res.send({ error: "403", data: { msg: `No data sent`, }, }); return; } // Check if we have all we need const params = ["username", "password", "classId"]; for (let param of params) { if (!(param in req.body)) { res.send({ error: "403", data: { msg: `${param} not specified!`, }, }); return; } } const { username, password, classId } = req.body; // Check if the registration is open for the class Id // NOTE: Thiis to prevent people from spamming the database const classes = env["LATEINICUS_CLASSES"].split(","); if (classes.indexOf(classId) !== -1) { res.send({ error: "403", data: { msg: "Class does not exist", }, }); return; } // TODO: Check if the username is profane // if (profanityFilter.isProfane(username)) { // res.send({ // error: "451", // data: { // msg: "Profane username", // }, // }); // return; // } // Check if the user already exists const checkUser = await db.collection("users").findOne({ username, }); if (checkUser) { res.send({ error: "403", data: { msg: "User already exists", }, }); return; } const salt = randomBytes(30).toString("hex"); const hash = pbkdf2Sync(password, salt, 50000, 512, "sha512").toString("hex"); const user = { username, salt, hash, classId, score: 0, showWelcome: true, lastReview: { correct: 0, wrong: 0, }, lastLevel: 0, levels: [] as number[], vocabMetadata: {}, }; await db.collection("users").insertOne(user); res.send({ error: "200", data: {}, }); }); app.get("/api/health", (req, res) => { res.send({ error: "0", data: { msg: "lol", }, }); }); app.post("/api/login", async (req, res) => { // Check if all arguments were sent const { body } = req; if (!body || !("username" in body) || !("password" in body)) { res.send({ error: "400", data: { msg: "Username or password not specified", }, }); return; } // Try to log the user in try { const userData = await performLogin(body.username, body.password, db); res.send({ error: "0", data: userData, }); } catch (err) { console.log("Could not resolve login promise!", err); // If anything was wrong, just tell the client res.send({ error: "1", data: { msg: "Username or password is wrong", }, }); } }); const server = app.listen(8080, () => { console.log("Starting on port 8080"); }); })();