~chrono/boiler

a898bd9e4cb197bee59b265d62291ef2ed88e525 — Chrono 1 year, 1 month ago 172f494
testing

6 files changed, 97 insertions(+), 63 deletions(-)

D import-sorter.json
M src/db/db.ts
M src/routes/api.ts
M src/routes/auth.ts
M src/server.ts
M src/socket.ts
D import-sorter.json => import-sorter.json +0 -14
@@ 1,14 0,0 @@
{
  "importStringConfiguration": {
    "trailingComma": "none",
    "tabSize": 4,
    "maximumNumberOfImportExpressionsPerLine": {
      "count": 50
    }
  },
  "sortConfiguration": {
    "customOrderingRules": {
      "defaultNumberOfEmptyLinesAfterGroup": 2
    }
  }
}

M src/db/db.ts => src/db/db.ts +3 -3
@@ 7,10 7,10 @@
// external imports
// import bcrypt from 'bcrypt';
import * as bcrypt from "https://deno.land/x/bcrypt@v0.4.1/mod.ts";
import { v4 as uuidv4 } from 'uuid';

// internal imports
import { Channel, PermissionsObject, User } from "../structures/structures.ts";
import generateSnowflake from "../util/snowflake.ts";
import { getUserById, users } from "./users.ts";

// Data structure to store channels


@@ 58,7 58,7 @@ async function addUser(
		bcrypt
			.hash(password, salt)
			.then((hash: string) => {
				const id = generateSnowflake();
				const id = uuidv4();

				// Add user to database
				users.set(


@@ 138,7 138,7 @@ function createChannel(
				const channel = new Channel(
					name,
					description,
					generateSnowflake(),
					uuidv4(),
					user.Member
				);


M src/routes/api.ts => src/routes/api.ts +12 -4
@@ 33,14 33,22 @@ const communicator = new EventEmitter();
router.use(express.json());
router.use(auth);

// definition of the type of the request object
declare global {
	namespace Express {
		interface Request {
			authenticated: boolean;
			query: { username: string; password: string };
		}
	}
}


// API status endpoint
router.get(
	"/",
	(
		request: Request & {
			authenticated: boolean;
			query: { username: string; password: string };
		},
		request: Request,
		res: Response
	) => {
		const status = {

M src/routes/auth.ts => src/routes/auth.ts +34 -34
@@ 18,7 18,6 @@ import {
	getUserByToken,
} from "../db/db.ts";
import { getUserByEmail } from "../db/users.ts";
import { type User } from "../structures/structures.ts";

dotenv.config();



@@ 50,44 49,45 @@ router.get(
);

// Login endpoint
router.post("/login/email", (request: Request, res: Response) => {
router.post("/login/email", async (request: Request, res: Response) => {
	const { username, password } = request.body;

	getUserByEmail(username)
		.then(async (user: User) => {
			// Check if password is correct
			if ((await checkPassword(password, user.hash)) == true) {
				// Generate token
				const token = jwt.sign(
					{
						username: user.username,
						id: user.id,
						permissions: user.permissions,
					},
					process.env.JWT_SECRET,
					{
						expiresIn: "12h",
					}
				);

				// Assign token to user
				user.token = token;

				// Send token
				res.status(200).json({
					token,
					username: user.username,
					id: user.id,
				});
			} else {
				res.status(401).json({ error: "Incorrect password" });
	const user = await getUserByEmail(username);

	if (!user) {
		res.status(404).json({ error: "User not found" });
	}

	// Check if password is correct
	if ((await checkPassword(password, user.hash)) == true) {
		// Generate token
		const token = jwt.sign(
			{
				username: user.username,
				id: user.id,
				permissions: user.permissions,
			},
			process.env.JWT_SECRET,
			{
				expiresIn: "12h",
			}
		})
		.catch((error) => {
			console.log(error);
		);

		// Assign token to user
		user.token = token;

			return res.status(401).json({ error: "User does not exist" });
		// Send token
		res.status(200).json({
			token: token,
			username: user.username,
			id: user.id,
		});

		// finish request
		return;
	} else {
		res.status(401).json({ error: "Incorrect password" });
	}
});

// Register endpoint

M src/server.ts => src/server.ts +47 -7
@@ 30,12 30,11 @@ import { getUserById, users } from "./db/users.ts";
import { api, com } from "./routes/api.ts";
import { authRouter } from "./routes/auth.ts";
import socketHandler from "./socket.ts";
import { type Channel, type User } from "./structures/structures.ts";

// check that we're running Node.js 18 or higher
if (Number.parseInt(process.versions.node.split(".")[0]) < 18) {
	const err = new Error(
		"Hammer requires Node.js 18 or higher to run. Please update your Node.js installation.",
		"Hammer requires Node.js 18 or higher to run. Please update your Node.js installation."
	);

	console.log(err);


@@ 65,8 64,10 @@ app.use(express.json());
// Listen for connections
wss.on(
	"connection",
	(	ws: WebSocket & { json: (data: unknown) => void } & EventEmitter,
		request: http.IncomingMessage & { url: string } ) => {
	(
		ws: WebSocket & { json: (data: unknown) => void } & EventEmitter,
		request: http.IncomingMessage & { url: string }
	) => {
		const url = new URL(request.url, `http://${request.headers.host}`);
		const token = url.searchParams.get("token");



@@ 254,9 255,6 @@ app.use("/app/login", express.static(path.join(__dirname, "./app/login.html")));
// set x-powered-by header setting
app.disable("x-powered-by");

// set x-powered-by header to Express
app.set("x-powered-by", "Express");

// Start the server
const listener = app.listen(port + 1, () => {
	// Print the banner


@@ 275,12 273,16 @@ const listener = app.listen(port + 1, () => {
	console.log("Server API is listening on http://localhost:" + ePort);
});

/*
addUser("admin@disilla.org", "admin", "password", {
	ADMINISTRATOR: true,
	MANAGE_CHANNELS: true,
	MANAGE_MESSAGES: true,
})
	.then((user: User) => {

		console.log("Admin user created.");

		createChannel(
			{ name: "general", description: "The general channel" },
			user.id


@@ 307,3 309,41 @@ addUser("admin@disilla.org", "admin", "password", {
	.catch((error) => {
		console.log(error);
	});
	*/

(async () => {
	const user = await addUser("admin@disilla.org", "admin", "password", {
		ADMINISTRATOR: true,
		MANAGE_CHANNELS: true,
		MANAGE_MESSAGES: true,
	});

	const name = (await getUserById(user.id)).username;
	if(name == "admin") {
		console.log("Admin user created.");
	}

	const channel = await createChannel(
		{ name: "general", description: "The general channel" },
		user.id
	);

	await addUserToChannel(channel.id, user.id);
	com.emit("channelJoin", { user: user.id, channel: channel.id });

	const nuser = await addUser("me@disilla.org", "chrono", "password", {
		ADMINISTRATOR: false,
		MANAGE_CHANNELS: false,
		MANAGE_MESSAGES: false,
	});

	const name1 = (await getUserById(nuser.id)).username;
	if(name1 == "chrono") {
		console.log("Chrono user created.");
	}

	await addUserToChannel(channel.id, nuser.id);
	com.emit("channelJoin", { user: nuser.id, channel: channel.id });

	console.log("Async/await test complete.");
})();

M src/socket.ts => src/socket.ts +1 -1
@@ 1,5 1,5 @@
/*
 * Hammer - A simple WebSocket-based chat server & client written in JavaScript.
 * Hammer - A simple WebSocket-based chat server & client written in TypeScript.
 *
 * Copyright (C) 2023 Hammer Authors <chrono@disilla.org>
 */