diff --git a/CTF/CTF-Frontend/src/app/Helper/ContestSetup.ts b/CTF/CTF-Frontend/src/app/Helper/ContestSetup.ts index f446337..64d0d16 100644 --- a/CTF/CTF-Frontend/src/app/Helper/ContestSetup.ts +++ b/CTF/CTF-Frontend/src/app/Helper/ContestSetup.ts @@ -183,7 +183,7 @@ export async function setNewFlag(flag: Flag, el: ElementRef, elements: any, ts: const email = getEmail(); const data = { FlagImage: flag.Image, email: email }; - const res = await fetch('api/setNewActiveFlag', { + const res = await fetch('api/flags/setNewActiveFlag', { method: 'POST', headers: { 'Content-Type' : 'application/json' @@ -279,14 +279,14 @@ async function checkSubmission(isPractice: boolean, el: ElementRef, socket: Sock } let res, result; if(!isPractice){ - res = await fetch('api/checkFlagSubmission', { + res = await fetch('api/submissions/checkFlagSubmission', { method: 'POST', headers: { 'Content-Type': 'application/json'}, body: JSON.stringify({ email, flagID, submittedFlag }) }); } else{ - res = await fetch('api/checkPracSubmission', { + res = await fetch('api/submissions/checkPracSubmission', { method: 'POST', headers: { 'Content-Type': 'application/json'}, body: JSON.stringify({ email, flagID, submittedFlag }) diff --git a/CTF/CTF-Frontend/src/app/add-contest/add-contest.component.ts b/CTF/CTF-Frontend/src/app/add-contest/add-contest.component.ts index cb1abeb..8e2359e 100644 --- a/CTF/CTF-Frontend/src/app/add-contest/add-contest.component.ts +++ b/CTF/CTF-Frontend/src/app/add-contest/add-contest.component.ts @@ -20,7 +20,7 @@ export class AddContestComponent { const isActive = 0; console.log("EMAIL IS:", this.getEmail()) const data = {Name: name, IsActive: isActive, email: this.getEmail(), Desc: desc}; - const res = await fetch('api/AddContest', { + const res = await fetch('api/contests/AddContest', { method: 'POST', headers: { 'Content-Type' : 'application/json' diff --git a/CTF/CTF-Frontend/src/app/add-flag/add-flag.component.html b/CTF/CTF-Frontend/src/app/add-flag/add-flag.component.html index edc2d97..151cc3b 100644 --- a/CTF/CTF-Frontend/src/app/add-flag/add-flag.component.html +++ b/CTF/CTF-Frontend/src/app/add-flag/add-flag.component.html @@ -50,10 +50,16 @@ +<<<<<<< HEAD + + +>>>>>>> 39ac6351e5793d9f00c090384c69686e0baa4a6c

diff --git a/CTF/CTF-Frontend/src/app/add-flag/add-flag.component.ts b/CTF/CTF-Frontend/src/app/add-flag/add-flag.component.ts index 2275f9f..3155d58 100644 --- a/CTF/CTF-Frontend/src/app/add-flag/add-flag.component.ts +++ b/CTF/CTF-Frontend/src/app/add-flag/add-flag.component.ts @@ -1,9 +1,8 @@ import { Component } from '@angular/core'; -import { gotoPage } from '../Helper/Helpers'; +import { gotoPage, getEmail } from '../Helper/Helpers'; import { Router } from '@angular/router'; import { ModifyContestService } from '../modify-contest/modify-contest.service'; import { Image } from '../models/image.model'; -import { getEmail } from '../Helper/Helpers'; import { NgFor, CommonModule } from '@angular/common'; import { FormsModule } from '@angular/forms'; @@ -50,7 +49,7 @@ export class AddFlagComponent { // add the flag const data = {name: flagName.value, desc: description.value, contest: contestId, image: image.value, path: path.value, hint1: Hint1.value || '', hint2: Hint2.value || '', hint3: Hint3.value || ''}; try{ - const response = await fetch('api/AddFlag', { + const response = await fetch('api/flags/AddFlag', { method: 'POST', headers: {'Content-Type': 'application/json',}, body: JSON.stringify(data) @@ -70,7 +69,21 @@ export class AddFlagComponent { } } + async getImages(): Promise{ + const email = this.getEmail(); + try{ + const imageData = await this.modifyContestService.getImages(email); + this.images = imageData || []; + }catch(error){ + console.error('Error loading images'); + } + } + navtoPageCI(){ gotoPage(this.router, '/create-image'); } + + getEmail(): string{ + return getEmail(); + } } diff --git a/CTF/CTF-Frontend/src/app/add-student/add-student.component.ts b/CTF/CTF-Frontend/src/app/add-student/add-student.component.ts index f91f3a2..9d7fd3c 100644 --- a/CTF/CTF-Frontend/src/app/add-student/add-student.component.ts +++ b/CTF/CTF-Frontend/src/app/add-student/add-student.component.ts @@ -36,7 +36,7 @@ export class AddStudentComponent { if (this.password == this.confirmPassword) { // passwords match const data = {name: this.Uname, email: this.email, Aemail: Aemail, password: this.password}; - const res = await fetch('api/AddStudent', { + const res = await fetch('api/users/AddStudent', { method: 'POST', headers: { 'Content-Type' : 'application/json' diff --git a/CTF/CTF-Frontend/src/app/admin-profile/admin-profile.component.ts b/CTF/CTF-Frontend/src/app/admin-profile/admin-profile.component.ts index 1e77e43..adf2a45 100644 --- a/CTF/CTF-Frontend/src/app/admin-profile/admin-profile.component.ts +++ b/CTF/CTF-Frontend/src/app/admin-profile/admin-profile.component.ts @@ -33,7 +33,6 @@ export class AdminProfileComponent implements OnInit{ this.populateTable(); } - async populateTable(){ try{ const email = this.getEmail(); @@ -54,6 +53,8 @@ export class AdminProfileComponent implements OnInit{ const result = await this.adminProfileService.getContestFlagsSubs(email, this.selectedContest); this.flags = result.flags; this.subs = result.subs; + console.log("flags", this.flags); + console.log("Subs", this.subs); }catch(error){ console.error('Failed to populate flag table'); } diff --git a/CTF/CTF-Frontend/src/app/create-image/create-image.component.ts b/CTF/CTF-Frontend/src/app/create-image/create-image.component.ts index 647ec58..09b0094 100644 --- a/CTF/CTF-Frontend/src/app/create-image/create-image.component.ts +++ b/CTF/CTF-Frontend/src/app/create-image/create-image.component.ts @@ -281,7 +281,7 @@ export class CreateImageComponent { formdata.append('data', JSON.stringify(data)); // send the post request - const res = await fetch('api/AddImage', { + const res = await fetch('api/images/AddImage', { method: 'POST', body: formdata }); diff --git a/CTF/CTF-Frontend/src/app/edit-student/edit-student.component.ts b/CTF/CTF-Frontend/src/app/edit-student/edit-student.component.ts index 58de85d..ea9ef41 100644 --- a/CTF/CTF-Frontend/src/app/edit-student/edit-student.component.ts +++ b/CTF/CTF-Frontend/src/app/edit-student/edit-student.component.ts @@ -25,7 +25,7 @@ export class EditStudentComponent { if (ps1 == ps2) { // if both passwords are equal, continue const data = { email: this.emailinput, password: ps1}; - const res = await fetch('api/UpdateStudent', { + const res = await fetch('api/users/UpdateStudent', { method: "POST", headers: { 'Content-Type' : 'application/json' diff --git a/CTF/CTF-Frontend/src/app/modify-contest/modify-contest.component.ts b/CTF/CTF-Frontend/src/app/modify-contest/modify-contest.component.ts index a7310a2..96b10a9 100644 --- a/CTF/CTF-Frontend/src/app/modify-contest/modify-contest.component.ts +++ b/CTF/CTF-Frontend/src/app/modify-contest/modify-contest.component.ts @@ -112,9 +112,13 @@ handlePopupMessage(event: MessageEvent): void { if (this.selectedContestId !== null) { try { const email = this.getEmail(); - await this.modifyContestService.setContestActive(this.selectedContestId, email); - this.loadContests(); - console.log('Contest set as active'); + const actOrDeact = await this.modifyContestService.setContestActive(this.selectedContestId, email); + if(actOrDeact === 1){ + this.loadContests(); + console.log('Contest set as active'); + } + else if(actOrDeact === 0) + this.activeContest = null; } catch (error) { console.error('Error activating contest:', error); } diff --git a/CTF/CTF-Frontend/src/app/modify-contest/modify-contest.service.ts b/CTF/CTF-Frontend/src/app/modify-contest/modify-contest.service.ts index 1e27248..39d7395 100644 --- a/CTF/CTF-Frontend/src/app/modify-contest/modify-contest.service.ts +++ b/CTF/CTF-Frontend/src/app/modify-contest/modify-contest.service.ts @@ -9,7 +9,7 @@ export class ModifyContestService { async getImages(email: string): Promise { try { - const response = await fetch('api/getImages', { + const response = await fetch('api/images/getImages', { method: 'POST', headers: { 'Content-Type': 'application/json' @@ -71,7 +71,7 @@ export class ModifyContestService { async addContest(data: any): Promise { try { - const response = await fetch('api/AddContest', { + const response = await fetch('api/constests/AddContest', { method: 'POST', headers: { 'Content-Type': 'application/json' @@ -93,7 +93,7 @@ export class ModifyContestService { // Send a POST request to delete the contest by its name let data = {contest: contestId}; await this.deleteFlagsFromContest(contestId); - let res = await fetch('api/DeleteContest', { + let res = await fetch('api/contests/DeleteContest', { method: 'POST', headers: { 'Content-Type': 'application/json', @@ -111,7 +111,7 @@ export class ModifyContestService { async deleteFlagsFromContest(contestId: number): Promise { try { - const response = await fetch('api/DeleteFlagsFromContest', { + const response = await fetch('api/flags/DeleteFlagsFromContest', { method: 'POST', headers: { 'Content-Type': 'application/json' @@ -131,7 +131,7 @@ export class ModifyContestService { async AddFlag(data: any): Promise { try { - const response = await fetch('api/AddFlag', { + const response = await fetch('api/flags/AddFlag', { method: 'POST', headers: { 'Content-Type': 'application/json' @@ -151,7 +151,7 @@ export class ModifyContestService { async DeleteFlag(flagId: number): Promise { let data = { flag: flagId }; - let res = await fetch('api/DeleteFlag', { + let res = await fetch('api/flags/DeleteFlag', { method: 'POST', headers: { 'Content-Type': 'application/json', @@ -164,7 +164,7 @@ export class ModifyContestService { const image = flagImage; // set up the container for the image const data = { FlagImage: image, email: Email }; - const res = await fetch('/api/setNewActiveFlag', { + const res = await fetch('/api/flags/setNewActiveFlag', { method: 'POST', headers: { 'Content-Type' : 'application/json' @@ -174,28 +174,50 @@ export class ModifyContestService { } async setContestActive(contestId: number, email: string): Promise { - try { - const response = await fetch('api/setContestActive', { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ contest: contestId, email }) - }); - - if (!response.ok) { - throw new Error('Failed to set contest active'); - } - return await response.json(); - } catch (error) { - console.error('Error setting contest active:', error); + const oldcontestID = await this.getActiveContest(email); + if(oldcontestID !== 0 && oldcontestID === contestId){ + try{ + const response = await fetch('api/contests/EndContest', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({contest: oldcontestID, email}) + }); + if(!response.ok) + throw new Error('Failed to end contest'); + await response.json(); + return 0; + }catch(error){ + console.error('Error ending contest'); throw error; } + } + else{ + try { + const response = await fetch('api/contests/setContestActive', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ contest: contestId, email }) + }); + + if (!response.ok) { + throw new Error('Failed to set contest active'); + } + await response.json(); + return 1; + } catch (error) { + console.error('Error setting contest active:', error); + throw error; + } + } } async deleteImage(imageName: string | undefined): Promise { try { - const response = await fetch('api/DeleteImageReplaceFlags', { + const response = await fetch('api/images/DeleteImageReplaceFlags', { method: 'POST', headers: { 'Content-Type': 'application/json' diff --git a/CTF/CTF-Frontend/src/app/unauthorized/unauthorized.component.html b/CTF/CTF-Frontend/src/app/unauthorized/unauthorized.component.html index 81bbd6e..74dd97f 100644 --- a/CTF/CTF-Frontend/src/app/unauthorized/unauthorized.component.html +++ b/CTF/CTF-Frontend/src/app/unauthorized/unauthorized.component.html @@ -1,3 +1 @@ -

Thought you could pull a fast one eh?

-

I dont think so

-

👎

\ No newline at end of file +

You do not have permission to access this page.

\ No newline at end of file diff --git a/CTF/CTF-Server/AdminImages/1/Root/jo.txt b/CTF/CTF-Server/AdminImages/1/Root/jo.txt new file mode 100644 index 0000000..b1fe6e3 --- /dev/null +++ b/CTF/CTF-Server/AdminImages/1/Root/jo.txt @@ -0,0 +1 @@ +jo [FLAG] \ No newline at end of file diff --git a/CTF/CTF-Server/AdminImages/2/Root/pythonprint.py b/CTF/CTF-Server/AdminImages/1/Root/pythonprint.py similarity index 100% rename from CTF/CTF-Server/AdminImages/2/Root/pythonprint.py rename to CTF/CTF-Server/AdminImages/1/Root/pythonprint.py diff --git a/CTF/CTF-Server/AdminImages/2/pythonprintmoreflag183301.dockerfile b/CTF/CTF-Server/AdminImages/1/jo223000.dockerfile similarity index 100% rename from CTF/CTF-Server/AdminImages/2/pythonprintmoreflag183301.dockerfile rename to CTF/CTF-Server/AdminImages/1/jo223000.dockerfile diff --git a/CTF/CTF-Server/AdminImages/1/pythonprintmoreflag183301.dockerfile b/CTF/CTF-Server/AdminImages/1/pythonprintmoreflag183301.dockerfile new file mode 100644 index 0000000..9cb50eb --- /dev/null +++ b/CTF/CTF-Server/AdminImages/1/pythonprintmoreflag183301.dockerfile @@ -0,0 +1,4 @@ +FROM ubuntu:latest +WORKDIR /. +CMD ["bin/bash"] +COPY Root /. diff --git a/CTF/CTF-Server/containers/containers.js b/CTF/CTF-Server/containers/containers.js new file mode 100644 index 0000000..02d6240 --- /dev/null +++ b/CTF/CTF-Server/containers/containers.js @@ -0,0 +1,73 @@ +import { getUsername } from "../server.js" +import { getActiveFlagImage } from "../queries/imageQueries.js" +import Docker from 'dockerode'; +// create a new docker +const docker = new Docker(); + +// creating container +async function CreateContainer(email) { + console.log('Creating Container for ' + email); + let username = getUsername(email); + + // get the active flag image for that user and use that to create the container + return getActiveFlagImage(email).then(async (image) => { + if(image === undefined || image.ActiveFlag === null || image.ActiveFlag === 'ubuntu') { + return await StartContainer('ubuntu', username, email); + } + else + return await StartContainer(image.ActiveFlag, username, email); + }).catch((err) => { + console.error('Error in CreateContainer:', err.message); + }); +} + +// Create and Start the container with correct image +async function StartContainer(image, username, email) { + + // create container + try { + const container = await docker.createContainer({ + Image: image, + Cmd: ['/bin/bash'], + AttachStdin: true, + AttachStdout: true, + AttachStderr: true, + StdinOnce: false, + OpenStdin: true, + Tty: true, + Detach: false, + Hostname: username, + name: username + }); + + // start container + console.log('starting container', container.id); + await container.start(); + console.log('+++++ Container started for ' + username + ' with ID: ' + container.id + ' +++++'); + return container; + } catch (err) { + if (err.statusCode === 409 || err.statusCode === 404) { // confliction or if container doesn't exist + return CheckContainer(email); + } + else console.error(err); + } +} + +// check if there is a container already created and started with the specific email +export async function CheckContainer(email) { + try { // remove container if that container already exists + console.log('Checking container for email:', email); + const cont = await docker.getContainer(getUsername(email)); + const info = await cont.inspect(); + if(info.State.Running){ + await cont.kill(); + await cont.remove({ force: true}); + } + return await CreateContainer(email); + } catch(err) { + if(err.statusCode === 404) { + return await CreateContainer(email); + } + console.error('Error checking container:', err.message); + } +}; \ No newline at end of file diff --git a/CTF/CTF-Server/db/db.js b/CTF/CTF-Server/db/dbconnection.js similarity index 100% rename from CTF/CTF-Server/db/db.js rename to CTF/CTF-Server/db/dbconnection.js diff --git a/CTF/CTF-Server/gets/contestQueries.js b/CTF/CTF-Server/gets/contestQueries.js deleted file mode 100644 index c0adf37..0000000 --- a/CTF/CTF-Server/gets/contestQueries.js +++ /dev/null @@ -1,124 +0,0 @@ -import con from '../db/db.js'; -import { Router } from "express"; -import { AdminorUser } from '../server.js'; -import { getAdminFromUser, getAdminID } from './adminQueries.js'; -const router = Router(); - -// get all contests for specific Admin -router.post('/getContests', async (req,res) => { - const { email } = req.body; - - // determine if email is admin or user - return AdminorUser(email).then(async (ans) => { - - // if user then go into the user table and grab the foreign key for Admin - if (ans === 'Users') { - - // get all the contests for that Admin - const Admin = await getAdminFromUser(email); - //if(!Admin || !Admin.AdminID) return res.status(404).json({error: 'Admin not found'}); - const query = 'SELECT * FROM Contests WHERE AdminID = ?'; - con.query(query, [Admin.AdminID], (err, rows) => { - if (err) { - console.error(err.message); - return res.status(500).json({ error: 'GETTING CONTESTS' }); - } - if (rows.length === 0) - return res.status(404).json({ error: 'NO CONTESTS FOUND' }); - return res.json(rows); - }); - } - // if email is an Admin - else { - // get all contests for that Admin - const Admin_1 = await getAdminID(email); - const query_1 = 'SELECT * FROM Contests WHERE AdminID = ?'; - con.query(query_1, [Admin_1.AdminID], (err_1, rows_1) => { - if (err_1) { - console.error(err_1.message); - return res.status(500).json({ error: 'GETTING CONTESTS' }); - } - if (rows_1.length === 0) - return res.status(404).json({ error: 'NO CONTESTS FOUND' }); - return res.json(rows_1); - }); - } - }).catch((err) => { - console.error(err); - return res.status(500).json({ error: 'COULD NOT GET CONTESTS' }); - }); -}); - -router.post('/getContestByID', async (req, res) => { - const { contestID } = req.body; - if(!contestID) - return res.status(400).json({error: 'No Contest ID'}); - try{ - const contest = await getContestByID(contestID); - res.json(contest); - } catch(err){ - if(err.message === 'Contest not found'){ - return res.status(404).json({ error: 'Contest not found' }); - } - else{ - console.error(err); - res.status(500).json({ error: 'Internal server error' }); - } - } -}); - -async function getContestByID(contestID){ - return new Promise((resolve, reject) => { - const query = 'SELECT * FROM Contests WHERE ContestID = ?'; - con.query(query, [contestID], (err, rows) => { - if(err) { - console.error(err.message); - reject(err); - } - if(rows.length === 0){ - return reject(new Error('Contest not found')); - } - resolve(rows[0]); - }); - }); -} - -// get the current active contest of an Admin -router.post('/getActiveContest', (req,res) => { - const { email } = req.body; - return AdminorUser(email).then((ans) => { - if (ans === 'Users') { - return getAdminFromUser(email).then((Admin) => { - const query = 'SELECT * FROM Contests WHERE IsActive = 1 AND AdminID = ?'; - con.query(query, [Admin.AdminID], (err,rows) => { - if (err) { - console.error(err.message); - return res.status(500).json({ error: 'GETTING ACTIVE CONTEST' }); - } - if (rows.length === 0) - return res.status(404).json({ error: 'NO CONTEST FOUND' }); - return res.json(rows[0]); - }) - }); - } - else { - return getAdminID(email).then((Admin) => { - const query = 'SELECT * FROM Contests WHERE IsActive = 1 AND AdminID = ?'; - con.query(query, [Admin.AdminID], (err,rows) => { - if (err) { - console.log('here'); - console.error(err.message); - return res.status(500).json({ error: 'GETTING ACTIVE CONTEST' }); - } - if(rows.length === 0) return res.status(404).json({ error: 'NO CONTEST FOUND' }); - else return res.json(rows[0]); - }); - }); - } - }).catch((err) => { - console.error(err.message); - return res.status(500).json({ error: 'GETTING ACTIVE CONTEST' }); - }); -}); - -export default router; \ No newline at end of file diff --git a/CTF/CTF-Server/gets/flagQueries.js b/CTF/CTF-Server/gets/flagQueries.js deleted file mode 100644 index 0d0a88e..0000000 --- a/CTF/CTF-Server/gets/flagQueries.js +++ /dev/null @@ -1,98 +0,0 @@ -import con from '../db/db.js'; -import { Router } from "express"; -import { AdminorUser } from '../server.js'; -const router = Router(); - -// get the active flag of a specific user -router.post('/getActiveFlag', (req,res) => { - const { email, contest } = req.body; - return AdminorUser(email).then((table) => { - const query = `SELECT ActiveFlag FROM ${table} WHERE Email = ?`; - con.query(query, [email, contest], (err,rows) => { - if (err) { - console.log(err.message); - return res.status(500).json({ error: 'GETTING ACTIVE FLAG' }); - } - if (rows.length > 0 && rows[0].ActiveFlag !== null) { - const activeFlag = rows[0].ActiveFlag; - const imageObject = { ActiveFlag: activeFlag}; - return getFlagByImage(imageObject).then((flag) => { - res.json(flag); - }); - } - else return res.status(500).json({ error: 'GETTING ACTIVE FLAG' }); - }); - }); -}); - -// get every flag for a specific contest -router.post('/getAllFlagsFromContest', (req,res) => { - const { contest } = req.body; - const query = 'SELECT * FROM Flags WHERE ContestID = ?'; - con.query(query, [contest], (err,rows) => { - if (err) { - console.error(err.message); - return res.status(500).json({ error: 'GETTING ALL FLAGS FOR CONTEST' }); - } - res.json(rows); - }); -}); - -// get a flag by the image name -export async function getFlagByImage(image) { - //console.log("looking for your image: ", image.ActiveFlag); - const flagImage = image.ActiveFlag; - return new Promise((resolve, reject) => { - const query = 'SELECT * FROM Flags WHERE Image = ?'; - con.query(query, [flagImage], (err,rows) => { - if (err) { - console.error(err.message); - reject(err); - } - if(rows.length === 0) - return resolve('ubuntu'); - resolve(rows[0]); - }); - }); -} - -// get all of the flags -export async function getAllFlags() { - return new Promise((resolve, reject) => { - const query = 'SELECT * FROM Flags'; - con.query(query, [], (err,rows) => { - if (err) { - console.error(err.message); - reject(err); - } - resolve(rows); - }); - }); -}; - -// get every flag for a specific contest -router.post('/getAllFlagsFromContest', (req,res) => { - const { contest } = req.body; - const query = 'SELECT * FROM Flags WHERE ContestID = ?'; - con.query(query, [contest], (err,rows) => { - if (err) { - console.error(err.message); - return res.status(500).json({ error: 'GETTING ALL FLAGS FOR CONTEST' }); - } - res.json(rows); - }); -}); - -// get every flag inside db -router.get('/getAllFlags', (req,res) => { - const query = 'SELECT * FROM Flags'; - con.query(query, [], (err,rows) => { - if (err) { - console.error(err.message); - return res.status(500).json({ error: 'GETTING ALL FLAGS FROM DB' }); - } - res.json(rows); - }); -}); - -export default router; \ No newline at end of file diff --git a/CTF/CTF-Server/gets/userQueries.js b/CTF/CTF-Server/gets/userQueries.js deleted file mode 100644 index 7df3f92..0000000 --- a/CTF/CTF-Server/gets/userQueries.js +++ /dev/null @@ -1,99 +0,0 @@ -import con from '../db/db.js'; -import { Router } from "express"; -import { getAdminID } from "./adminQueries.js"; -const router = Router(); - -// get a user from either table with email -export function getUserByEmail(table, email) { - return new Promise((resolve, reject) => { - const query = `SELECT * FROM ${table} WHERE Email = ?`; - con.query(query, [email], (err, rows) => { - if (err) { - console.error(err.message); - reject(err); - } - resolve(rows[0]); - }); - }); -} - -// delete a student from the database -router.post('/DeleteStudent', (req,res) => { - const {email} = req.body; - const query = "DELETE FROM Users WHERE Users.Email = ?"; - con.query(query, [email], function(err,rows) { - if (err) { - console.error(err.message); - return res.status(500).json({ error: "DELETING STUDENT" }); - } - - // contest doesn't exist - if (rows.affectedRows === 0) return res.status(404).json({ error: "NO STUDENT" }); - return res.status(200).json({ success: true }); - }); -}) - -// get all of the users with the same key as admin -router.post('/getAllUsers', (req,res) => { - const { email } = req.body; - return getAdminID(email).then((Admin) => { - const query = 'SELECT * FROM Users WHERE AdminID = ?'; - con.query(query,[Admin.AdminID], (err,rows) => { - if (err) { - console.error(err.message); - return res.status(500).json({ error: 'GETTING USERS '}); - } - if(rows.length === 0) - res.status(404).json({ error: 'NO ADMIN/USERS FOUND '}); - else - res.json(rows); - }); - }); -}); - -// return everything on a user by email -router.post('/getUser', async(req,res) => { - const { email } = req.body; - return getUserByEmail('Users',email).then((row) => { - if (row) res.json(row); - else return res.status(404).json({ error: 'USER NOT FOUND' }); - }) -}); - -router.post('/getUsername', async(req,res) => { - const { email } = req.body; - return getUserByEmail('Users',email).then((row) => { - if (row) res.json(row.Name); - else return res.status(404).json({ error: 'USER NOT FOUND' }); - }) -}); - -// set the new name of the user -router.post('/setUserName', (req,res) => { - const { name, email } = req.body; - const query = 'UPDATE Users SET Name = ? WHERE Email = ?'; - con.query(query, [name,email], (err) => { - if (err){ - console.error(err.message); - return res.status(500).json({ error: err }); - } - return res.status(200).json({ success: true }); - }); -}); - - -// get all users from an AdminID -export async function getUsersFromAdmin(AdminID) { - return new Promise((resolve,reject) => { - const query = 'SELECT * FROM Users WHERE AdminID = ?'; - con.query(query, [AdminID], (err,rows) => { - if (err) { - console.error(err.message); - reject(err); - } - resolve(rows); - }) - }); -} - -export default router; \ No newline at end of file diff --git a/CTF/CTF-Server/package-lock.json b/CTF/CTF-Server/package-lock.json index 9502780..ac6db4c 100644 --- a/CTF/CTF-Server/package-lock.json +++ b/CTF/CTF-Server/package-lock.json @@ -15,6 +15,7 @@ "docker-stream-cleanser": "^1.0.1", "dockerode": "^4.0.4", "express": "^4.21.2", + "express-session": "^1.18.1", "jsonwebtoken": "^9.0.2", "multer": "^1.4.5-lts.1", "mysql": "^2.18.1", @@ -1076,6 +1077,55 @@ "url": "https://opencollective.com/express" } }, + "node_modules/express-session": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.1.tgz", + "integrity": "sha512-a5mtTqEaZvBCL9A9aqkrtfz+3SMDhOVUnjafjo+s7A9Txkq+SVX2DLvSp1Zrv4uCXa3lMSK3viWnh9Gg07PBUA==", + "license": "MIT", + "dependencies": { + "cookie": "0.7.2", + "cookie-signature": "1.0.7", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-headers": "~1.0.2", + "parseurl": "~1.3.3", + "safe-buffer": "5.2.1", + "uid-safe": "~2.1.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/express-session/node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express-session/node_modules/cookie-signature": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", + "license": "MIT" + }, + "node_modules/express-session/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express-session/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, "node_modules/express/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -1952,6 +2002,15 @@ "node": ">= 0.8" } }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -2053,6 +2112,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/random-bytes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", + "integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -2653,6 +2721,18 @@ "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", "license": "MIT" }, + "node_modules/uid-safe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", + "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", + "license": "MIT", + "dependencies": { + "random-bytes": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/undici-types": { "version": "6.21.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", diff --git a/CTF/CTF-Server/package.json b/CTF/CTF-Server/package.json index e560533..bf5f9da 100644 --- a/CTF/CTF-Server/package.json +++ b/CTF/CTF-Server/package.json @@ -17,6 +17,7 @@ "docker-stream-cleanser": "^1.0.1", "dockerode": "^4.0.4", "express": "^4.21.2", + "express-session": "^1.18.1", "jsonwebtoken": "^9.0.2", "multer": "^1.4.5-lts.1", "mysql": "^2.18.1", diff --git a/CTF/CTF-Server/gets/adminQueries.js b/CTF/CTF-Server/queries/adminQueries.js similarity index 82% rename from CTF/CTF-Server/gets/adminQueries.js rename to CTF/CTF-Server/queries/adminQueries.js index 3ad4573..e43f314 100644 --- a/CTF/CTF-Server/gets/adminQueries.js +++ b/CTF/CTF-Server/queries/adminQueries.js @@ -1,6 +1,4 @@ -import con from '../db/db.js'; -import { Router } from "express"; -const router = Router(); +import con from '../db/dbconnection.js'; // get the Admin foreign key from User table export async function getAdminFromUser(email) { @@ -25,9 +23,7 @@ export async function getAdminID(email) { console.error(err.message); reject(err); } - resolve(rows[0]); + resolve(rows[0].AdminID); }); }); -} - -export default router; \ No newline at end of file +} \ No newline at end of file diff --git a/CTF/CTF-Server/queries/contestQueries.js b/CTF/CTF-Server/queries/contestQueries.js new file mode 100644 index 0000000..dc8f50a --- /dev/null +++ b/CTF/CTF-Server/queries/contestQueries.js @@ -0,0 +1,114 @@ +import con from '../db/dbconnection.js'; +import { AdminorUser } from '../server.js'; +import { getAdminID } from './adminQueries.js'; + +export async function getContestByID(contestID){ + return new Promise((resolve, reject) => { + const query = 'SELECT * FROM Contests WHERE ContestID = ?'; + con.query(query, [contestID], (err, rows) => { + if(err) { + console.error(err.message); + reject(err); + } + if(rows.length === 0) + return reject(new Error('Contest not found')); + resolve(rows[0]); + }); + }); +} + +export async function addContest(Name, AdminID, Desc){ + return new Promise((resolve, reject) => { + const query = 'INSERT INTO CONTESTS (Name, IsActive, AdminID, Description) VALUES (?,0,?,?)'; + con.query(query, [Name, AdminID, Desc], (err, res) => { + if(err) reject(err); + else resolve(res); + }) + }) +} + +export async function getActiveContest(adminID){ + return new Promise((res, reject) => { + const query = 'SELECT * FROM Contests WHERE IsActive = 1 AND AdminID = ?'; + con.query(query, [adminID], (err, rows) => { + if(err) reject(err); + else res(rows); + }) + }) +} + +export async function endContest(adminID, contestID){ + console.log("ContestID:", contestID); + return new Promise((resolve, reject) => { + const query = 'UPDATE Contests SET IsActive = 0 WHERE AdminID = ? AND ContestID = ?'; + con.query(query, [adminID, contestID], (err, result) => { + if(err) reject(err); + else { + console.log("Ended:", result); + resolve(result); + } + }); + }); +} + +export async function setContestActive(adminID, contestID){ + return new Promise((resolve, reject) => { + const query = 'UPDATE Contests SET IsActive = 1 WHERE AdminID = ? AND ContestID = ?'; + con.query(query, [adminID, contestID], (err, result) => { + if (err) reject(err); + else resolve(result); + }); + }); +} + +export async function deleteContest(contestID){ + return new Promise((resolve, reject) => { + const query = 'DELETE FROM Contests WHERE ContestID = ?'; + con.query(query, [contestID], (err, result) => { + if (err) reject(err); + else resolve(result); + }); + }); +} + +// get the contest ID from the contest name +export async function getContestIDFromName(contestname) { + return new Promise((resolve,reject) => { + const query = 'SELECT ContestID FROM Contests WHERE Name = ?'; + con.query(query,[contestname],(err,row) => { + if (err) { + console.error(err.message); + reject(err); + } + resolve(row); + }); + }); +} + +// get contest ID from an email and the name of the contest +export async function getContestIDFromNameAdminID(email, contestname) { + console.log("EMAIL:", email); + console.log("CONTEST:", contestname); + return getAdminID(email).then((Admin) => { + return new Promise((resolve,reject) => { + const query = 'SELECT ContestID FROM Contests WHERE AdminID = ? AND Name = ?'; + con.query(query,[Admin,contestname], (err,row) => { + if (err) { + console.error(err.message); + reject(err); + } + resolve(row[0].ContestID); + }); + }) + }); +} + +export async function getContestsFromAdminID(AdminID){ + return new Promise((resolve, reject) => { + const query = 'SELECT * FROM Contests WHERE AdminID = ?'; + con.query(query, [AdminID], (err, result) => { + if (err) reject(err); + else resolve(result); + }); + }); +} \ No newline at end of file diff --git a/CTF/CTF-Server/queries/flagQueries.js b/CTF/CTF-Server/queries/flagQueries.js new file mode 100644 index 0000000..5e60f0c --- /dev/null +++ b/CTF/CTF-Server/queries/flagQueries.js @@ -0,0 +1,124 @@ +import con from '../db/dbconnection.js'; +import { AdminorUser } from '../server.js'; + +// get a flag by the image name +export async function getFlagByImage(image) { + //console.log("looking for your image: ", image.ActiveFlag); + const flagImage = image.ActiveFlag; + return new Promise((resolve, reject) => { + const query = 'SELECT * FROM Flags WHERE Image = ?'; + con.query(query, [flagImage], (err,rows) => { + if (err) { + console.error(err.message); + reject(err); + } + if(rows.length === 0) + return resolve('ubuntu'); + resolve(rows[0]); + }); + }); +} + +// get all of the flags +export async function getAllFlags() { + return new Promise((resolve, reject) => { + const query = 'SELECT * FROM Flags'; + con.query(query, [], (err,rows) => { + if (err) { + console.error(err.message); + reject(err); + } + resolve(rows); + }); + }); +}; + +export async function addFlag(name, desc, contest, image, path, hint1, hint2, hint3){ + return new Promise((resolve, reject) => { + const query = 'INSERT INTO FLAGS (Name, Description, ContestID, Image, Path, Hint1, Hint2, Hint3) VALUES (?,?,?,?,?,?,?,?)'; + con.query(query, [name, desc, contest, image, path, hint1, hint2, hint3], (err, result) => { + if(err) reject(err); + else resolve(result); + }); + }); +} + +// delete flags attempts from submissions +export async function DeleteFlagFromSub(flag) { + const query = 'DELETE FROM Submissions WHERE FlagID = ?'; + con.query(query, [flag], (err) => { + if (err) { + console.error(err.message); + } + }); +} + +export async function getActiveFlag(email, table){ + return new Promise((resolve, reject) => { + const query = `SELECT ActiveFlag FROM ${table} WHERE Email = ?`; + con.query(query, [email], (err, rows) => { + if(err) reject(err); + if(rows.length > 0 && rows[0].ActiveFlag !== null){ + resolve(rows[0].ActiveFlag) + } + else reject("no active flag found"); + }); + }); +} + +export async function setNewActiveFlag(FlagImage, email, table){ + return new Promise((resolve, reject) => { + const query = `UPDATE ${table} SET ActiveFlag = ? WHERE Email = ?`; + console.log('New image:', FlagImage); + con.query(query, [FlagImage, email], (err, result) => { + if(err) reject(err); + else resolve(result); + }); + }); +} + +export async function clearActiveFlag(email){ + const table = await AdminorUser(email); + return new Promise((resolve, reject) => { + const query = `UPDATE ${table} SET ActiveFlag = ? WHERE Email = ?`; + con.query(query, ['ubuntu', email], (err, result) => { + if(err) reject(err); + else resolve(result); + }); + }); +} + + +export async function deleteFlag(flag){ + return new Promise((resolve, reject) => { + const query = 'DELETE FROM Flags WHERE FlagID = ?'; + con.query(query, [flag], (err, result) => { + if(err) reject(err); + else resolve(result); + }); + }); +} + +export async function deleteFlagsFromContest(contest){ + return new Promise((resolve, reject) => { + const query = 'DELETE FROM Flags WHERE ContestID = ?'; + con.query(query, [contest], (err, result) => { + if(err) reject(err); + else resolve(result); + }); + }); +} + +// get a flag from a specific contest +export async function getFlagFromContestID(contestID) { + return new Promise((resolve, reject) => { + const query = 'SELECT * FROM Flags WHERE ContestID = ?'; + con.query(query, [contestID], (err,rows) => { + if (err) { + console.error(err.message); + reject(err); + } + resolve(rows); + }); + }); +} \ No newline at end of file diff --git a/CTF/CTF-Server/queries/imageQueries.js b/CTF/CTF-Server/queries/imageQueries.js new file mode 100644 index 0000000..0a11121 --- /dev/null +++ b/CTF/CTF-Server/queries/imageQueries.js @@ -0,0 +1,73 @@ +import con from "../db/dbconnection.js"; + +export async function getImagesForAdmin(adminID){ + return new Promise((resolve, reject) => { + console.log("Checking for Admin: ", adminID); + const query = 'SELECT Name FROM Images WHERE AdminID = ?'; + con.query(query, [adminID], (err, result) => {; + if(err) reject(err); + else { + resolve(result); + } + }); + }); +} + +// get the active flag from specific user +export async function getActiveFlagImage(email) { + console.log(`Getting active flag for ${email}`); + return new Promise((resolve, reject) => { + const query = 'SELECT ActiveFlag FROM Users WHERE Email = ?'; + con.query(query, [email], (err,rows) => { // check users table + if (err) { // error + console.error('Error fetching from Users table: ', err.message); + reject(err); + } + if (rows.length === 0) { + console.log('no active flag for user, checking admins...'); + const query = 'SELECT ActiveFlag FROM Admins WHERE Email = ?'; + con.query(query, [email], (err,rows) => { // check admins table + if (err) { // error + console.error('Error fetching from Admins table: ', err.message); + reject(err); + } + resolve(rows[0]); + }) + } + else{ + console.log('Active flag from users table: ', rows[0]); + resolve(rows[0]); + } + }); + }); +} + +// add the image name to the db of images +export async function AddImage(Admin,imgname) { + const query = 'INSERT INTO Images (Name,AdminID) VALUES (?,?)'; + con.query(query, [imgname,Admin], (err) => { + if (err) { + console.error(err.message); + } + }) +} + +// reset the flag to ubuntu image +export async function ResetFlagImage(flag) { + const query = 'UPDATE Flags SET Image = ? WHERE FlagID = ?'; + con.query(query, ['ubuntu', flag.FlagID], (err) => { + if (err) { + console.error(err.message); + } + }); +} + +// delete an image from the database +export async function DeleteImage(image) { + const query = 'DELETE FROM Images WHERE Name = ?'; + con.query(query, [image], (err) => { + if (err) { + console.error(err.message); + } + }); +} \ No newline at end of file diff --git a/CTF/CTF-Server/queries/submissionQueries.js b/CTF/CTF-Server/queries/submissionQueries.js new file mode 100644 index 0000000..9fe5010 --- /dev/null +++ b/CTF/CTF-Server/queries/submissionQueries.js @@ -0,0 +1,55 @@ +import con from "../db/dbconnection.js"; + +export async function getSubmissions(userID, flagID){ + return new Promise((resolve, reject) => { + const query = 'SELECT * FROM Submissions WHERE UserID = ? AND FlagID = ?'; + con.query(query, [userID, flagID], (err, result) => { + if(err) reject(err); + else resolve(result); + }); + }); +} + +export async function insertSubmission(userID, flagID, isCorrect, attempts){ + return new Promise((resolve, reject) => { + const query = 'INSERT INTO Submissions (UserID, FlagID, IsCorrect, Attempts) VALUES (?, ?, ?, ?)'; + con.query(query, [userID, flagID, isCorrect, attempts], (err, result) => { + if(err) reject(err); + else resolve(); + }); + }); +} + +export async function updateSubmissionCorrect(userID, flagID){ + return new Promise((resolve, reject) => { + const query = 'UPDATE Submissions SET IsCorrect = 1 WHERE UserID = ? AND FlagID = ?'; + con.query(query, [userID, flagID], (err, result) => { + if(err) reject(err); + else resolve(); + }); + }); +} + +export async function updateSubmissionAttempts(userID, flagID){ + return new Promise((resolve, reject) => { + const query = 'UPDATE Submissions SET Attempts = Attempts + 1 WHERE UserID = ? AND FlagID = ?'; + con.query(query, [userID, flagID], (err, result) => { + if(err) reject(err); + else resolve(); + }); + }); +} + +// get all of the submissions +export async function getAllSubs() { + return new Promise((resolve,reject) => { + const query = 'SELECT * FROM Submissions'; + con.query(query,[],(err,rows) => { + if (err) { + console.error(err.message); + reject(err); + } + resolve(rows); + }) + }); +} \ No newline at end of file diff --git a/CTF/CTF-Server/queries/userQueries.js b/CTF/CTF-Server/queries/userQueries.js new file mode 100644 index 0000000..de4758f --- /dev/null +++ b/CTF/CTF-Server/queries/userQueries.js @@ -0,0 +1,92 @@ +import con from '../db/dbconnection.js'; + +// get a user from either table with email +export function getUserByEmail(table, email) { + return new Promise((resolve, reject) => { + const query = `SELECT * FROM ${table} WHERE Email = ?`; + con.query(query, [email], (err, rows) => { + if (err) { + console.error(err.message); + reject(err); + } + resolve(rows[0]); + }); + }); +} + + +// get all users from an AdminID +export async function getUsersFromAdmin(AdminID) { + return new Promise((resolve,reject) => { + const query = 'SELECT * FROM Users WHERE AdminID = ?'; + con.query(query, [AdminID], (err,rows) => { + if (err) { + console.error(err.message); + reject(err); + } + resolve(rows); + }) + }); +} + +export async function setUserName(name, email){ + return new Promise((resolve, reject) => { + const query = 'UPDATE Users SET Name = ? WHERE Email = ?'; + con.query(query, [name, email], (err) => { + if(err) reject(err); + else resolve(); + }); + }); +} + + +export async function addStudent(name, email, password, admin){ + return new Promise((resolve, reject) => { + const query = `INSERT INTO Users (Name, Email, Password, Flags, AdminID) VALUES (?,?,?,0,?)`; + con.query(query, [name, email, password, admin], (err, result) => { + if(err) reject(err); + else resolve(result); + }); + }); +} + +export async function updateStudent(email, password){ + return new Promise((resolve, reject) => { + const query = 'UPDATE Users SET Password = ? WHERE Email = ?'; + con.query(query, [password, email], (err, result) => { + if(err) reject(err); + else resolve(result); + }); + }); +} + +export async function getUserID(email){ + return new Promise((resolve, reject) => { + const userQuery = 'SELECT UserID FROM Users WHERE Email = ?'; + con.query(query, [email], (err, result) => { + if(err) reject(err); + else resolve(result); + }); + }); +} + + +export async function updateUserFlags(userID) { + return new Promise((resolve, reject) => { + const query = 'UPDATE Users SET Flags = Flags + 1 WHERE UserID = ?'; + con.query(query, [userID], (err) => { + if (err) reject(err); + else resolve(); + }); + }); +} + +export async function deleteStudent(email) { + return new Promise((resolve, reject) => { + const query = "DELETE FROM Users WHERE Email = ?"; + con.query(query, [email], (err, result) => { + if (err) reject(err); + else resolve(result); + }); + }); +} \ No newline at end of file diff --git a/CTF/CTF-Server/routes/contestHandler.js b/CTF/CTF-Server/routes/contestHandler.js new file mode 100644 index 0000000..d54cb02 --- /dev/null +++ b/CTF/CTF-Server/routes/contestHandler.js @@ -0,0 +1,140 @@ +import { getContestsFromAdminID, addContest, getActiveContest, endContest, setContestActive, deleteContest, getContestByID } from "../queries/contestQueries.js"; +import { AdminorUser } from "../server.js"; +import {getAdminID, getAdminFromUser} from "../queries/adminQueries.js"; +import { Router } from "express"; +const router = Router(); + +// add a contest to the database +router.post('/AddContest', async (req,res) => { + try{ + const { Name, IsActive, email, Desc } = req.body; + const Admin = await getAdminID(email); + console.log("Admin is:", Admin); + await addContest(Name, Admin, Desc) + res.status(200).json({success: true}); + } catch(err){ + console.error(err.message); + res.status(500).json({error: "Could not insert contest"}) + } +}); + +// end a current active contest +router.post('/EndContest', async (req,res) => { + try{ + const { contest, email } = req.body; + const Admin = await getAdminID(email); + console.log("ADMIN ID:", Admin); + if(!Admin) return res.status(404).json({error: "admin not found"}); + const activeContest = await getActiveContest(Admin); + if(activeContest.length === 0) + return res.status(404).json({error: "CONTEST NOT FOUND"}); + if(activeContest.IsActive === 0) + return res.status(400).json({ error: 'CONTEST ALREADY INACTIVE' }); + const result = await endContest(Admin, contest); + if(result.affectedRows === 0) + return res.status(404).json({error: "CONTEST NOT FOUND"}); + return res.status(200).json({success: true}); + } catch(err){ + console.error(err.message); + return res.status(500).json({error: "ENDING CONTEST"}); + } +}); + +// Set a specific contest active for a specific Admin +router.post('/setContestActive', async (req,res) => { + try{ + const { contest, email } = req.body; + const Admin = await getAdminID(email); + const activeContest = await getActiveContest(Admin); + console.log("Active contests", activeContest); + if(activeContest.length > 0) + await endContest(Admin, activeContest[0].ContestID); + const result = await setContestActive(Admin, contest); + if(result.affectedRows === 0) return res.status(404).json({ error: "CONTEST NOT FOUND"}); + return res.status(200).json({success: true}); + } catch(err){ + console.error(err.message); + return res.status(500).json({error: "Error setting contest active"}); + } +}); + +// delete a specific contest from database +router.post('/DeleteContest', async (req,res) => { + try{ + const { contest } = req.body; + const result = await deleteContest(contest); + if(result.affectedRows === 0){ + return res.status(404).json({error: "CONTEST NOT FOUND"}); + } + return res.status(200).json({success: true}); + } catch(err){ + console.error(err.message); + return res.status(500).json({ error: "ERROR DELETING CONTEST"}); + } +}); + +// get all contests for specific Admin +router.post('/getContests', async (req,res) => { + const { email } = req.body; + try{ + let AdminID; + const table = await AdminorUser(email); + if(table == 'Users'){ + const admin = await getAdminFromUser(email); + AdminID = admin.AdminID; + } + else{ + AdminID = await getAdminID(email); + } + const contests = await getContestsFromAdminID(AdminID); + if(contests.length === 0){ + return res.status(404).json({error: "NO CONTESTS FOUND"}); + } + return res.json(contests); + } catch(err){ + console.error(err); + return res.status(500).json({error: "COULD NOT GET CONTESTS"}); + } +}); + +router.get('/getContestByID', async (req, res) => { + const { contestID } = req.body; + if(!contestID) + return res.status(400).json({error: 'No Contest ID'}); + try{ + const contest = await getContestByID(contestID); + res.json(contest); + } catch(err){ + if(err.message === 'Contest not found'){ + return res.status(404).json({ error: 'Contest not found' }); + } + else{ + console.error(err); + res.status(500).json({ error: 'Internal server error' }); + } + } +}); + +router.post('/getActiveContest', async (req, res) => { + const { email } = req.body; + try { + const table = await AdminorUser(email); + let AdminID; + if (table === 'Users') { + const admin = await getAdminFromUser(email); + AdminID = admin.AdminID; + } else { + AdminID = await getAdminID(email); + } + const contests = await getActiveContest(AdminID); + if (contests.length === 0) { + return res.status(200).json({ message: 'No active contests found' }); + } + res.json(contests[0]); + } catch (err) { + console.error(err.message); + return res.status(500).json({ error: 'An error occurred while fetching the active contest' }); + } +}); + +export default router; diff --git a/CTF/CTF-Server/routes/flagHandler.js b/CTF/CTF-Server/routes/flagHandler.js new file mode 100644 index 0000000..bde8123 --- /dev/null +++ b/CTF/CTF-Server/routes/flagHandler.js @@ -0,0 +1,117 @@ +import { AdminorUser } from "../server.js"; +import { Router } from "express"; +import { addFlag, setNewActiveFlag, clearActiveFlag, getFlagFromContestID, deleteFlagsFromContest, DeleteFlagFromSub, deleteFlag, getAllFlags, getFlagByImage, getActiveFlag} from "../queries/flagQueries.js" +const router = Router(); +// add a new flag to a specific contest +router.post('/AddFlag', (req,res) => { + const { name, desc, contest, image, path, hint1, hint2, hint3} = req.body; + // getting all the hints, whether how many + let Hint1 = hint1 || ''; + let Hint2 = hint2 || ''; + let Hint3 = hint3 || ''; + console.log("got here"); + addFlag(name, desc, contest, image, path, Hint1, Hint2, Hint3) + .then(result => { + return res.status(200).json({success: true, result}); + }).catch(err => { + console.error(err.message); + return res.status(500).json({error: "COULD NOT ADD FLAG"}); + }); +}); + +// Set new flag for specific user ActiveFlag +router.post('/setNewActiveFlag', async (req,res) => { + const { FlagImage, email } = req.body; + return AdminorUser(email).then((table) => { + return setNewActiveFlag(FlagImage, email, table) + }).then(result => { + console.log('Flag update:', result); + return res.status(200).json({success: true, result}); + }).catch(err => { + console.error(err.message); + return res.status(500).json({error: "COULD NOT SET FLAG ACTIVE"}); + }); +}); + +router.post('/clearActiveFlag', async(req, res) => { + const {email} = req.body; + try{ + const result = await clearActiveFlag(email); + return res.status(200).json({success: true}); + }catch(err){ + console.error("Error clearing flag:", err.message); + return res.status(500).json({error: "Could not clear active flag"}); + } +}); + +// delete all flags from a specific contest +router.post('/DeleteFlagsFromContest', async (req,res) => { + const { contest } = req.body; + try{ + console.log("Contest:", contest); + // get all flags first and delete them from submissions + const flags = await getFlagFromContestID(contest); + console.log("Flags:", flags); + for (var i = 0; i < flags.length; i++) + await DeleteFlagFromSub(flags[i].FlagID); + const result = await deleteFlagsFromContest(contest); + console.log("Result", result); + if(result.affectedRows === 0) + return res.status(200).json({ success: true, message: "No flags found for this contest"}); + return res.status(200).json({success: true}); + } catch(err){ + console.error("Error deleting flags from contest:", err.message); + return res.status(500).json({error: "COULD NOT DELETE FLAGS"}); + } +}); + +// get every flag inside db +router.get('/getAllFlags', async (req,res) => { + try{ + const flags = await getAllFlags(); + res.json(flags); + } catch(err){ res.status(500).json({error: "FAILED TO GRAB FLAGS"})}; +}); + +// delete specific flag with FlagID +router.post('/DeleteFlag', (req,res) => { + const { flag } = req.body; + DeleteFlagFromSub(flag); + deleteFlag(flag).then(result => { + if(result.affectedRows === 0) + return res.status(404).json({error: "FLAG NOT FOUNT"}); + return res.status(200).json({success: true}); + }).catch(err => { + console.error("Error deleting flag:", err.message); + return res.status(500).json({error: "COULD NOT DELETE FLAG"}); + }); +}); + +// get the active flag of a specific user +router.post('/getActiveFlag', async (req,res) => { + const { email, contest } = req.body; + try{ + const table = await AdminorUser(email); + const activeFlag = await getActiveFlag(email, table); + if(activeFlag !== null){ + const imageObject = {ActiveFlag: activeFlag}; + const flag = await getFlagByImage(imageObject); + res.json(flag); + } + else res.status(500).json({error: "No active flag found"}); + }catch(err){ + console.error(err.message); + res.status(500).json({ error: "FAILED TO GET ACTIVE FLAG"}); + } +}); + +// get every flag for a specific contest +router.post('/getAllFlagsFromContest', async (req,res) => { + const { contest } = req.body; + try{ + const flags = await getFlagFromContestID(contest); + res.json(flags); + }catch(err) { res.status(500).json({error: "could not grab flags for contest"}); } +}); + +export default router; \ No newline at end of file diff --git a/CTF/CTF-Server/routes/imageHandler.js b/CTF/CTF-Server/routes/imageHandler.js new file mode 100644 index 0000000..a1c3fee --- /dev/null +++ b/CTF/CTF-Server/routes/imageHandler.js @@ -0,0 +1,66 @@ +import { getImagesForAdmin, DeleteImage, ResetFlagImage} from "../queries/imageQueries.js"; +import { getAdminID } from "../queries/adminQueries.js"; +import { getAllFlags } from "../queries/flagQueries.js"; +import { CreateImage } from "../server.js"; +import { Router } from "express"; +import multer from 'multer'; +const storage = multer.memoryStorage(); +const upload = multer({ storage }); +const router = Router(); + +// create an Image +router.post('/AddImage', upload.array("files"), (req,res) => { + + // parse the json data that came in and the files + const jsondata = req.body.data; + let parsedjsondata = JSON.parse(jsondata); + const files = req.files; + + // get all of the values + const root = parsedjsondata.root; + const imgname = parsedjsondata.imgname; + const email = parsedjsondata.email; + + // create image and return + CreateImage(root, imgname, email, files); + return res.status(200).json({ success: true }); +}); + +// get all images for Admin +router.post('/getImages', async (req,res) => { + const { email } = req.body; + try{ + const Admin = await getAdminID(email); + const images = await getImagesForAdmin(Admin); + res.json(images); + } catch(err){ + console.error("Error getting images:", err.message); + return res.status(500).json({error: "COULD NOT GET IMAGES"}); + } +}); + +// delete image and replace the image of the flag that's using it +router.post('/DeleteImageReplaceFlags', (req,res) => { + const { images } = req.body; + return getAllFlags().then((flags) => { + for (var i=0; i < flags.length; i++) { + // if the flag's image is being deleted change it to ubuntu + if (flags[i].Image === images) { + ResetFlagImage(flags[i]); + } + } + // delete the images from the database and from docker + if (images === 'ubuntu') return res.status(201).json({ success: true }); + else { + DeleteImage(images); + try { + execSync(`docker rmi -f ${images}`); + } catch (err) { + console.error(err.message); + } + } + return res.status(200).json({ success: true }); + }); +}); + +export default router; \ No newline at end of file diff --git a/CTF/CTF-Server/routes/loginHandler.js b/CTF/CTF-Server/routes/loginHandler.js index b282aee..5a49c62 100644 --- a/CTF/CTF-Server/routes/loginHandler.js +++ b/CTF/CTF-Server/routes/loginHandler.js @@ -1,5 +1,5 @@ import { Router } from "express"; -import { getUserByEmail } from '../gets/userQueries.js'; +import { getUserByEmail } from '../queries/userQueries.js'; import bcrypt from 'bcrypt'; const router = Router(); //create a router object to handle routes diff --git a/CTF/CTF-Server/routes/submissionHandler.js b/CTF/CTF-Server/routes/submissionHandler.js new file mode 100644 index 0000000..978c3bd --- /dev/null +++ b/CTF/CTF-Server/routes/submissionHandler.js @@ -0,0 +1,51 @@ +import { Router } from "express"; +import { getFlagHash } from "../server.js" +import { getUserID } from "../queries/userQueries.js"; +import { getSubmissions, insertSubmission, updateSubmissionAttempts } from "../queries/submissionQueries.js"; +const router = Router(); + +router.post('/checkFlagSubmission', async (req, res) => { + const { email, flagID, submittedFlag } = req.body; + try{ + const correctFlag = getFlagHash(email, flagID); + const userID = await getUserID(email); + + const submissions = await getSubmissions(userID, flagID); + if(submittedFlag === correctFlag){ + if(submissions.length === 0){ //If the submission is correct and it is their first submission. + await insertSubmission(userID, flagID, 1, 1); + await updateUserFlags(userID); + return res.json({correct: true, message: "Correct flag submitted!"}); + } + else{ //If the submission is correct and it is not their first submission + await updateSubmissionAttempts(userID, flagID); + await updateUserFlags(userID); + return res.json({correct: true, message: "Correct flag submitted!"}); + } + } + else{ + if(submissions.length === 0){ //If the submission is incorrect and it is their first submssion + await insertSubmission(userID, flagID, 0, 1); + return res.json({correct: false, message: "Incorrect flag. Try again!"}); + } + else{ //If their submission is incorrect and it is not their first submission + await updateSubmissionAttempts(userID, flagID); + return res.json({correct: false, message: "Incorrect flag. Try again!"}); + } + } + } catch(err){ + console.error("Could not add submission:", err); + return res.status(500).json({correct: false, message: "ERROR SUBMITTING FLAG"}); + } +}); + +router.post('/checkPracSubmission', async (req, res) => { + const { email, flagID, submittedFlag } = req.body; + const correctFlag = getFlagHash(email, flagID); + if(correctFlag === submittedFlag) + return res.json({correct: true, message: 'Correct flag submitted!'}); + else + return res.json({correct: false, message: 'Incorrect flag. Try Again'}); +}); + +export default router; \ No newline at end of file diff --git a/CTF/CTF-Server/routes/userHandler.js b/CTF/CTF-Server/routes/userHandler.js new file mode 100644 index 0000000..8bdff0f --- /dev/null +++ b/CTF/CTF-Server/routes/userHandler.js @@ -0,0 +1,98 @@ +import { deleteStudent, updateStudent, addStudent, setUserName, getUsersFromAdmin, getUserByEmail } from "../queries/userQueries.js"; +import { getAdminID } from "../queries/adminQueries.js"; +import { Router } from "express"; +import bcrypt from "bcrypt"; +const router = Router(); +// add a student to the database +router.post('/AddStudent', async (req,res) => { + const { name, email, Aemail, password } = req.body; + try{ + const Admin = await getAdminID(Aemail); + const saltRounds = 10; + const hashedPassword = await bcrypt.hash(password, saltRounds); + const result = await addStudent(name, email, hashedPassword, Admin); + return res.status(200).json({success: true}); + } catch(err){ + console.error("Error adding student", err.message); + return res.statusMessage(500).json({error: "Could not add student"}); + } +}); + +// update a student in the database +router.post('/UpdateStudent', async (req,res) => { + const { email, password } = req.body; + try{ + const saltRounds = 10; + const hashedPassword = await bcrypt.hash(password, saltRounds); + const result = await updateStudent(email, hashedPassword); + if(result.affectedRows === 0) + return res.status(404).json({error: "Student not found"}); + return res.status(200).json({success: true}); + } catch(err){ + console.error('Error updating student:', err.message); + return res.status(500).json({error: "Could not update password"}); + } +}); + +// delete a student from the database +router.post('/DeleteStudent', (req,res) => { + const {email} = req.body; + deleteStudent(email).then((result) => { + if(result.affectedRows === 0) + return res.status(404).json({error: "NO STUDENT"}); + return res.status(200).json({success: true}); + }).catch((err) => { + console.error(err.message); + return res.status(500).json({error: "COULD NOT DELETE STUDENT"}); + }); +}); + +// get all of the users with the same key as admin +router.post('/getAllUsers', (req,res) => { + const { email } = req.body; + return getAdminID(email).then((Admin) => { + return getUsersFromAdmin(Admin).then((users) => { + if(users.length === 0) + res.status(404).json({error: "NO ADMIN/USERS FOUND"}); + else + res.json(users); + }).catch((err) => { + console.error(err.message); + res.status(500).json({error: "COULD NOT FIND USER"}); + }); + }).catch((err) => { + console.error(err.message); + res.status(500).json({error: "COULD NOT FIND ADMIN"}); + }); +}); + +// return everything on a user by email +router.post('/getUser', async(req,res) => { + const { email } = req.body; + return getUserByEmail('Users',email).then((row) => { + if (row) res.json(row); + else return res.status(404).json({ error: 'USER NOT FOUND' }); + }) +}); + +router.post('/getUsername', async(req,res) => { + const { email } = req.body; + return getUserByEmail('Users',email).then((row) => { + if (row) res.json(row.Name); + else return res.status(404).json({ error: 'USER NOT FOUND' }); + }) +}); + +// set the new name of the user +router.post('/setUserName', async (req,res) => { + const { name, email } = req.body; + try{ + await setUserName(name, email); + res.status(200).json({success: true}); + }catch(err){ + console.error(err.message); + res.status(500).json({error: err.message}); + } +}); + +export default router; \ No newline at end of file diff --git a/CTF/CTF-Server/server.js b/CTF/CTF-Server/server.js index 83c88c7..699c428 100644 --- a/CTF/CTF-Server/server.js +++ b/CTF/CTF-Server/server.js @@ -7,39 +7,41 @@ ******************************************************************** */ -import login from "./routes/loginHandler.js"; -import contestQueries from "./gets/contestQueries.js"; -import flagQueries from "./gets/flagQueries.js"; -import userQueries from "./gets/userQueries.js"; -import adminQueries from "./gets/adminQueries.js"; -import con from "./db/db.js"; -import { getFlagByImage } from "./gets/flagQueries.js"; -import { getAdminID } from "./gets/adminQueries.js"; -import bcrypt from 'bcrypt'; - // IP and PORT const port = 3000; const ioport = 3001; const ip = 'localhost'; // imports +import login from "./routes/loginHandler.js"; +import contestHandler from "./routes/contestHandler.js"; +import flagHandler from "./routes/flagHandler.js"; +import userHandler from "./routes/userHandler.js"; +import submissionHandler from "./routes/submissionHandler.js" +import imageHandler from "./routes/imageHandler.js"; +import con from "./db/dbconnection.js"; +import { getFlagByImage, clearActiveFlag, getFlagFromContestID } from "./queries/flagQueries.js"; +import { getAdminID } from "./queries/adminQueries.js"; +import { getActiveFlagImage, AddImage} from "./queries/imageQueries.js"; +import { getContestIDFromNameAdminID } from "./queries/contestQueries.js"; +import { getAllSubs } from "./queries/submissionQueries.js"; import path from 'path'; import express from 'express'; import http from 'http'; import cors from 'cors'; import crypto from 'crypto'; import fs from 'fs'; -import jwt from 'jsonwebtoken'; import multer from 'multer'; -import Docker from 'dockerode'; import DockerStreamCleanser from 'docker-stream-cleanser'; import { WebSocketServer } from 'ws'; import { exec } from 'child_process' import { fileURLToPath } from 'url'; +import { Session } from "express-session"; +import { CheckContainer } from "./containers/containers.js"; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); -const router = express.Router(); const app = express(); + // express stuff app.use(express.static(path.join(__dirname, '/'))); app.use(express.json()); @@ -58,15 +60,12 @@ const upload = multer({ storage }); // start the server with the socket const server = http.createServer(app); -//const io = socketIo(server); const wss = new WebSocketServer({ server }); // on connection to the server wss.on('connection', async (ws) => { console.log('***** Connection Made *****'); - ws.on('message', async (message) => { - // get the first message into the socket let messagestring = Buffer.isBuffer(message) ? message.toString('utf-8') : message; messagestring = messagestring.substring(1,messagestring.length-1); @@ -78,7 +77,6 @@ wss.on('connection', async (ws) => { getActiveFlagImage(messagestring).then((image) => { placeFlag(messagestring, container, image); }); - container.exec({ Cmd: ['/bin/bash'], AttachStdin: true, @@ -149,121 +147,28 @@ wss.on('connection', async (ws) => { ******************************************************************** */ -//ROUTES -app.use("/login", login); - -app.use('/contests', contestQueries); - -app.use('/flags', flagQueries); - -app.use('/users', userQueries); - -app.use('/admins', adminQueries); - -// Admin Contest page -app.get('/Admin_Contest', (req, res) => { - res.sendFile(__dirname + '/(A)Contest_Page.html'); -}); - -// User Contest page -app.get('/User_Contest', (req, res) => { - res.sendFile(__dirname + '/contest-page.html'); -}); - -// User menu page -app.get('/User_Menu', (req, res) => { - res.sendFile(__dirname + '/User_Menu.html'); -}); - -// User Menu Screen -app.get('/User_Contest', (req, res) => { - res.sendFile(__dirname + '/User_Menu.html'); -}) - -// Admin Modify Contest Screen -app.get('/Admin_Contest', (req, res) => { - res.sendFile(__dirname + '/Modify_Contests.html') -}); +/*app.use(Session({ secret: 'key', + resave: false, + saveUninitialized: false, + cookie: { secure: false, maxAge: 100 * 60 * 60 } //10 minutes + }));*/ +//ROUTES +app.use("/login", login); -/* -******************************************************************** - Docker Containers -******************************************************************** -*/ - -// create a new docker -const docker = new Docker(); +app.use('/contests', contestHandler); -// creating container -async function CreateContainer(email) { - console.log('Creating Container for ' + email); - let username = getUsername(email); - - // get the active flag image for that user and use that to create the container - return getActiveFlagImage(email).then(async (image) => { - if(image === undefined || image.ActiveFlag === null || image.ActiveFlag === 'ubuntu') { - return await StartContainer('ubuntu', username, email); - } - else - return await StartContainer(image.ActiveFlag, username, email); - }).catch((err) => { - console.error('Error in CreateContainer:', err.message); - }); -} +app.use('/flags', flagHandler); -// Create and Start the container with correct image -async function StartContainer(image, username, email) { +app.use('/users', userHandler); - // create container - try { - const container = await docker.createContainer({ - Image: image, - Cmd: ['/bin/bash'], - AttachStdin: true, - AttachStdout: true, - AttachStderr: true, - StdinOnce: false, - OpenStdin: true, - Tty: true, - Detach: false, - Hostname: username, - name: username - }); +app.use('/submissions', submissionHandler); - // start container - console.log('starting container', container.id); - await container.start(); - console.log('+++++ Container started for ' + username + ' with ID: ' + container.id + ' +++++'); - return container; - } catch (err) { - if (err.statusCode === 409 || err.statusCode === 404) { // confliction or if container doesn't exist - return CheckContainer(email); - } - else console.error(err); - } -} +app.use('/images', imageHandler); -// check if there is a container already created and started with the specific email -async function CheckContainer(email) { - try { // remove container if that container already exists - console.log('Checking container for email:', email); +//app.use('/admins', adminHandler); - const cont = await docker.getContainer(getUsername(email)); - const info = await cont.inspect(); - if(info.State.Running){ - await cont.kill(); - await cont.remove({ force: true}); - } - return await CreateContainer(email); - } catch(err) { - if(err.statusCode === 404) { - return await CreateContainer(email); - } - console.error('Error checking container:', err.message); - } -}; /* @@ -272,221 +177,15 @@ async function CheckContainer(email) { ******************************************************************** */ -// add a contest to the database -app.post('/AddContest', async (req,res) => { - const { Name, IsActive, email, Desc } = req.body; - const Admin = await getAdminID(email); - console.log("Admin is:", Admin); - const query = 'INSERT INTO CONTESTS (Name, IsActive, AdminID, Description) VALUES (?,0,?,?)'; - con.query(query, [Name, Admin.AdminID, Desc], (err) => { - if (err) { - console.error(err.message); - return res.status(500).json({ error: 'INSERTING NEW CONTEST' }); - } - return res.status(200).json({ success: true }); - }); -}); - -// Set a specific contest active for a specific Admin -app.post('/setContestActive', (req,res) => { - const { contest, email } = req.body; - return getAdminID(email).then((Admin) => { - const query = 'SELECT * FROM Contests WHERE IsActive = 1 AND AdminID = ?'; - con.query(query, [Admin.AdminID], (err,rows) => { - if (err) { - console.error(err.message); - return res.status(500).json({ error: 'SETTING CONTEST ACTIVE' }); - } - if (rows.length === 0){ - // if contest not active yet, set the new contest to active - const query = 'UPDATE Contests SET IsActive = 1 WHERE AdminID = ? AND ContestID = ?'; - con.query(query, [Admin.AdminID, contest], (err) => { - if (err) { - console.error(err.message); - return res.status(500).json({ error: 'UPDATING CONTEST ACTIVE' }); - } - if (rows.affectedRows === 0) return res.status(404).json({ error: 'CONTEST NOT FOUND' }); - else return res.status(200).json({ success: true }); - }); - } - - // if there is a contest active then deactivate that one first - else { - const query = 'UPDATE Contests SET IsActive = 0 WHERE AdminID = ? AND ContestID = ?'; - con.query(query, [Admin.AdminID,rows[0].ContestID], (err) => { - if (err) { - console.error(err.message); - return res.status(500).json({ error: 'SETTING OLD CONTEST TO INACTIVE' }); - } - const query = 'UPDATE Contests SET IsActive = 1 WHERE AdminID = ? AND ContestID = ?'; - con.query(query, [Admin.AdminID, contest], (err) => { - if (err) { - console.error(err.message); - return res.status(500).json({ error: 'UPDATING CONTEST ACTIVE' }); - } - if (rows.affectedRows === 0) return res.status(404).json({ error: 'CONTEST NOT FOUND' }); - else return res.status(200).json({ success: true }); - }); - }); - } - }); - - - }); -}); - -// end a current active contest -app.post('/EndContest', (req,res) => { - const { contest, email } = req.body; - const query = 'SELECT IsActive FROM Contests WHERE ContestID = ?'; - con.query(query, [contest], (err,rows) => { - if (err) { - console.error(err.message); - return res.status(500).json({ error: 'ENDING CONTEST' }); - } - - // no row found in db - if (rows.length === 0) return res.status(404).json({ error: 'CONTEST NOT FOUND' }); - - // contest is already InActive - if (rows[0].IsActive === 0) return res.status(400).json({ error: 'CONTEST ALREADY INACTIVE' }); - - // update which contest is active - else { - const query = 'UPDATE Contests SET IsActive = 0 WHERE ContestID = ?'; - con.query(query, [contest], (err, result) => { - if (err) { - console.error(err.message); - return res.status(500).json({ error: 'UPDATING CONTEST ISACTIVE' }); - } - - // contest doesn't exist - if (rows.affectedRows === 0) return res.status(404).json({ error: 'CONTEST NOT FOUND' }); - return res.status(200).json({ success: true }); - }); - } - - }); -}); - -// delete a specific contest from database -app.post('/DeleteContest', (req,res) => { - const { contest } = req.body; - const query = 'DELETE FROM Contests WHERE ContestID = ?'; - con.query(query, [contest], (err, rows) => { - if (err) { - console.error(err.message); - return res.status(500).json({ error: 'DELETING CONTEST' }); - } - - // contest doesn't exist - if (rows.affectedRows === 0) return res.status(404).json({ error: 'CONTEST NOT FOUND' }); - return res.status(200).json({ success: true }); - }); -}); - -// add a new flag to a specific contest -app.post('/AddFlag', (req,res) => { - const { name, desc, contest, image, path, hint1, hint2, hint3} = req.body; - - // getting all the hints, whether how many - let Hint1 = hint1 || ''; - let Hint2 = hint2 || ''; - let Hint3 = hint3 || ''; - - const query = 'INSERT INTO FLAGS (Name, Description, ContestID, Image, Path, Hint1, Hint2, Hint3) VALUES (?,?,?,?,?,?,?,?)'; - con.query(query, - [name, desc, contest, image, path, Hint1, Hint2, Hint3], (err) => { - if (err) { - console.error(err.message); - return res.status(500).json({ error: 'INESERTING NEW FLAG' }); - } - return res.status(200).json({ success: true }); - }); - -}); - -// Set new flag for specific user ActiveFlag -app.post('/setNewActiveFlag', (req,res) => { - const { FlagImage, email } = req.body; - return AdminorUser(email).then((table) => { - const query = `UPDATE ${table} SET ActiveFlag = ? WHERE Email = ?`; - console.log('New image:', FlagImage); - con.query(query, [FlagImage,email], (err,rows) => { - if (err) { - console.error(err.message); - return res.status(500).json({ error: 'SETTING ACTIVE FLAG' }); - } - return res.status(200).json({ success: true }); - }); - }); -}); - -app.post('/clearActiveFlag', (req, res) => { - const {email} = req.body; - console.log('Clearing active flag for:', email); - AdminorUser(email).then((table) => { - const query = `UPDATE ${table} SET ActiveFlag = ? WHERE Email = ?`; - con.query(query, ['ubuntu',email], (err, rows) => { - if(err) { - console.error('Error clearing active flag:', err.message); - return res.status(500).json({ error: 'CLEARING ACTIVE FLAG' }); - } - if(rows.affectedRows === 0) console.log('No rows updated'); - return res.status(200).json({ success: true }); - }) - }).catch(err => { - console.error('Error getting table:', err.message); - return res.status(500).json({error: 'Error getting table'}); - }) -}) - // get the contests and all the flags from that contest -app.post('/getContestFlagsSubs', (req,res) => { +app.post('/getContestFlagsSubs', async (req,res) => { const { email, contest } = req.body; - // get all of the contests - return getContestIDFromNameAdminID(email,contest).then((contestID) => { - return getFlagFromContestID(contestID.ContestID).then((flags) => { - return getAllSubs().then((subs) => { - return res.status(200).json({ flags: flags, subs: subs }); - }); - }); - }); -}); - - -// delete specific flag with FlagID -app.post('/DeleteFlag', (req,res) => { - const { flag } = req.body; - DeleteFlagFromSub(flag); - const query = 'DELETE FROM Flags WHERE FlagID = ?'; - con.query(query, [flag], (err, rows) => { - if (err) { - console.error(err.message); - return res.status(500).json({ error: 'DELETING FLAG' }); - } - if (rows.affectedRows === 0) return res.status(404).json({ error: 'FLAG NOT FOUND' }); - else return res.status(200).json({ success: true }); - }); -}); - -// delete all flags from a specific contest -app.post('/DeleteFlagsFromContest', async (req,res) => { - const { contest } = req.body; - - // get all flags first and delete them from submissions - const flags = await getFlagFromContestID(contest); - for (var i = 0; i < flags.length; i++) { - DeleteFlagFromSub(flags[i].FlagID); - } - // delete them from contest - const query = 'DELETE FROM Flags WHERE ContestID = ?'; - con.query(query, [contest], (err, rows) => { - if (err) { - console.error(err.message); - } - return res.status(200).json({ success: true }); + return getContestIDFromNameAdminID(email,contest).then(async (contestID) => { + console.log(contestID); + const flags = await getFlagFromContestID(contestID); + const subs = await getAllSubs(); + return res.status(200).json({ flags: flags, subs: subs }); }); }); @@ -525,82 +224,6 @@ app.post('/FillLeaderboard', (req,res) => { }); -// add a student to the database -app.post('/AddStudent', async (req,res) => { - const { name, email, Aemail, password } = req.body; - try{ - const Admin = await getAdminID(Aemail); - - const saltRounds = 10; - const hashedPassword = await bcrypt.hash(password, saltRounds); - const query = `INSERT INTO Users (Name, Email, Password, Flags, AdminID) VALUES (?,?,?,0,?)`; - con.query(query, [name, email, hashedPassword, Admin.AdminID], (err) => { - if (err) { - console.error(err.message); - return res.status(500).json({ error: 'INSERTING NEW STUDENT' }); - } - return res.status(200).json({ success: true }); - }); - } catch(err) { - console.error('Server error:', err); - return res.status(500).json({ error: 'Could not add student'}) - } -}); - -// update a student in the database -app.post('/UpdateStudent', async (req,res) => { - const { email, password } = req.body; - try{ - const saltRounds = 10; - const hashedPassword = await bcrypt.hash(password, saltRounds); - const query = 'UPDATE Users SET Password = ? WHERE Email = ?'; - con.query(query, [hashedPassword, email], (err) => { - if (err) { - console.error(err); - return res.status(500).json({ error: 'UPDATING STUDENT!' }); - } - return res.status(200).json({ success: true }); - }); - }catch(err){ - console.error('Error hashing password:', err); - return res.status(500).json({ error: 'Could not update password'}); - } -}); - -// create an Image -app.post('/AddImage', upload.array("files"), (req,res) => { - - // parse the json data that came in and the files - const jsondata = req.body.data; - let parsedjsondata = JSON.parse(jsondata); - const files = req.files; - - // get all of the values - const root = parsedjsondata.root; - const imgname = parsedjsondata.imgname; - const email = parsedjsondata.email; - - // create image and return - CreateImage(root, imgname, email, files); - return res.status(200).json({ success: true }); -}); - -// get all images for Admin -app.post('/getImages', (req,res) => { - const { email } = req.body; - getAdminID(email).then((Admin) => { - const query = 'SELECT Name FROM Images WHERE AdminID = ?'; - console.log(Admin); - con.query(query, [Admin.AdminID], (err,rows) => { - if (err) { - console.error(err.message); - return res.status(500).json({ error: 'GETTING IMAGES' }); - } - res.json(rows); - }); - }) -}); - app.post('/updateContainer/:email', async(req, res) => { const { email } = req.params; try{ @@ -612,206 +235,6 @@ app.post('/updateContainer/:email', async(req, res) => { } }) -// delete image and replace the image of the flag that's using it -app.post('/DeleteImageReplaceFlags', (req,res) => { - const { images } = req.body; - - return getAllFlags().then((flags) => { - for (var i=0; i < flags.length; i++) { - - // if the flag's image is being deleted change it to ubuntu - if (flags[i].Image === images) { - ResetFlagImage(flags[i]); - } - } - - // delete the images from the database and from docker - if (images === 'ubuntu') return res.status(201).json({ success: true }); - else { - DeleteImage(images); - try { - exec(`docker rmi -f ${images}`); - } catch (err) { - console.error(err.message); - } - } - - - return res.status(200).json({ success: true }); - }); -}); - -app.post('/checkFlagSubmission', async (req, res) => { - const { email, flagID, submittedFlag } = req.body; - const correctFlag = getFlagHash(email, flagID); - const userQuery = 'SELECT UserID FROM Users WHERE Email = ?'; - con.query(userQuery, [email], (err, userRows) => { - if(err) - return res.status(500).json({correct: false, message: 'Database error'}); - if(userRows.length === 0) - return res.json({correct: false, message: 'User not found'}); - const userID = userRows[0].UserID; - const submissionQuery = 'SELECT * FROM Submissions WHERE UserID = ? AND FlagID = ?'; - con.query(submissionQuery, [userID, flagID], (err, submissionsRows) => { - if(err) - return res.status(500).json({correct: false, message: 'Database error'}); - if(submittedFlag === correctFlag){ - if(submissionsRows.length === 0){ //If the submission is correct and it is their first submission. - const insertQuery = 'INSERT INTO Submissions (UserID, FlagID, IsCorrect, Attempts) VALUES (?, ?, 1, 1)'; - con.query(insertQuery, [userID, flagID], (err) => { - if(err) - return res.status(500).json({correct: false, message: 'Database error'}); - const updateFlagsQuery = 'UPDATE Users SET Flags = Flags + 1 WHERE UserID = ?'; - con.query(updateFlagsQuery, [userID], (err) => { - if(err) - return res.status(500).json({correct: false, message: 'Database errr'}); - return res.json({correct: true, message: 'Correct flag submitted!'}); - }); - }); - } - else{ //If the submission is correct and it is not their first submission - const updateQuery = 'UPDATE Submissions SET IsCorrect = 1, Attempts = Attempts + 1 WHERE UserID = ? AND FlagID = ?'; - con.query(updateQuery, [userID, flagID], (err) => { - const updateFlagsQuery = 'UPDATE Users SET Flags = Flags + 1 WHERE UserID = ?'; - con.query(updateFlagsQuery, [userID], (err) => { - if(err) - return res.status(500).json({correct: false, message: 'Database errr'}); - return res.json({correct: true, message: 'Correct flag submitted!'}); - }); - }); - } - } - else{ - if(submissionsRows.length === 0){ //If the submission is incorrect and it is their first submssion - const insertQuery = 'INSERT INTO Submissions (UserID, FlagID, IsCorrect, Attempts) VALUES (?, ?, 0, 1)'; - con.query(insertQuery, [userID, flagID], (err) => { - if(err) - return res.status(500).json({correct: false, message: 'Databsae error'}); - return res.json({correct: false, message: 'Incorrect flag. Try Again.'}); - }); - } - else { //If their submission is incorrect and it is not their first submission - const updateQuery = 'UPDATE Submissions SET Attempts = Attempts + 1 WHERE UserID = ? AND FlagID = ?'; - con.query(updateQuery, [userID, flagID], (err) => { - if(err) - return res.status(500).json({correct: false, message: 'Database error'}); - return res.json({correct: false, message: 'Incorrect flag. Try Again'}); - }); - } - } - }); - }); -}); - -app.post('/checkPracSubmission', async (req, res) => { - const { email, flagID, submittedFlag } = req.body; - const correctFlag = getFlagHash(email, flagID); - if(correctFlag === submittedFlag) - return res.json({correct: true, message: 'Correct flag submitted!'}); - else - return res.json({correct: false, message: 'Incorrect flag. Try Again'}); -}); - -/* -******************************************************************** - GET Requests for Database -******************************************************************** -*/ - -/* -******************************************************************** - Database Functions -******************************************************************** -*/ - -// get the active flag from specific user -async function getActiveFlagImage(email) { - console.log(`Getting active flag for ${email}`); - return new Promise((resolve, reject) => { - const query = 'SELECT ActiveFlag FROM Users WHERE Email = ?'; - con.query(query, [email], (err,rows) => { // check users table - if (err) { // error - console.error('Error fetching from Users table: ', err.message); - reject(err); - } - if (rows.length === 0) { - console.log('no active flag for user, checking admins...'); - const query = 'SELECT ActiveFlag FROM Admins WHERE Email = ?'; - con.query(query, [email], (err,rows) => { // check admins table - if (err) { // error - console.error('Error fetching from Admins table: ', err.message); - reject(err); - } - resolve(rows[0]); - }) - } - else{ - console.log('Active flag from users table: ', rows[0]); - resolve(rows[0]); - } - }); - }); - -} - -// get the contest ID from the contest name -async function getContestIDFromName(contestname) { - return new Promise((resolve,reject) => { - const query = 'SELECT ContestID FROM Contests WHERE Name = ?'; - con.query(query,[contestname],(err,row) => { - if (err) { - console.error(err.message); - reject(err); - } - resolve(row); - }); - }); -} - -// get contest ID from an email and the name of the contest -async function getContestIDFromNameAdminID(email, contestname) { - return getAdminID(email).then((Admin) => { - return new Promise((resolve,reject) => { - const query = 'SELECT ContestID FROM Contests WHERE AdminID = ? AND Name = ?'; - con.query(query,[Admin.AdminID,contestname], (err,row) => { - if (err) { - console.error(err.message); - reject(err); - } - resolve(row[0]); - }); - }) - }); -} - -// get a flag from a specific contest -async function getFlagFromContestID(contestID) { - return new Promise((resolve, reject) => { - const query = 'SELECT * FROM Flags WHERE ContestID = ?'; - con.query(query, [contestID], (err,rows) => { - if (err) { - console.error(err.message); - reject(err); - } - resolve(rows); - }); - }); -} - -// get all of the flags in the database -async function getAllFlags() { - return new Promise((resolve,reject) => { - const query = 'SELECT * FROM Flags'; - con.query(query, [], (err,rows) => { - if (err) { - console.error(err.message); - reject(err); - } - resolve(rows); - }); - }); -} - // get whether the email belongs to an admin or a user export async function AdminorUser(email) { return new Promise((resolve, reject) => { @@ -831,77 +254,6 @@ export async function AdminorUser(email) { }) } -async function clearActiveFlag(email){ - try{ - const table = await AdminorUser(email); - const query = `UPDATE ${table} SET ActiveFlag = ? WHERE Email = ?`; - con.query(query, ['ubuntu', email], (err, rows) => { - if(err) { - console.error('Error clearing flag', err.message); - return; - } - if(rows.affectedRows === 0) - console.log('No rows affected'); - console.log(`Active flag cleared for ${email}`); - }); - } catch (err) { console.error('Error clearing active flag', err.message); } -} - -// add the image name to the db of images -async function AddImage(Admin,imgname) { - const query = 'INSERT INTO Images (Name,AdminID) VALUES (?,?)'; - con.query(query, [imgname,Admin.AdminID], (err) => { - if (err) { - console.error(err.message); - } - }) -} - -// reset the flag to ubuntu image -async function ResetFlagImage(flag) { - const query = 'UPDATE Flags SET Image = ? WHERE FlagID = ?'; - con.query(query, ['ubuntu', flag.FlagID], (err) => { - if (err) { - console.error(err.message); - } - }); -} - -// delete an image from the database -async function DeleteImage(image) { - - const query = 'DELETE FROM Images WHERE Name = ?'; - con.query(query, [image], (err) => { - if (err) { - console.error(err.message); - } - }); -} - -// delete flags attempts from submissions -async function DeleteFlagFromSub(flag) { - const query = 'DELETE FROM Submissions WHERE FlagID = ?'; - con.query(query, [flag], (err) => { - if (err) { - console.error(err.message); - } - }); -} - -// get all of the submissions -async function getAllSubs() { - return new Promise((resolve,reject) => { - const query = 'SELECT * FROM Submissions'; - con.query(query,[],(err,rows) => { - if (err) { - console.error(err.message); - reject(err); - } - resolve(rows); - }) - }); -} - /* ******************************************************************** Functions @@ -909,7 +261,7 @@ async function getAllSubs() { */ // get the username portion of the email sent over -function getUsername(email) { +export function getUsername(email) { let username = ''; for (var i=0; i < email.length-1; i++) { if (email[i] != '@') username += email[i]; @@ -920,7 +272,7 @@ function getUsername(email) { } // Returns true if the string is an email -function IsEmail(email) { +export function IsEmail(email) { for (let i=0; i < email.length; i++) { if (email[i] === "@") return true; } @@ -928,7 +280,7 @@ function IsEmail(email) { } // create an image with the given tree -function CreateImage(root, imgname, email, files) { +export function CreateImage(root, imgname, email, files) { // get the Admin for database and file path getAdminID(email).then(async (Admin) => { @@ -936,10 +288,9 @@ function CreateImage(root, imgname, email, files) { // add the image to the database AddImage(Admin,imgname); - // go into directory and check if folder exists const ImageDir = path.join(__dirname, 'AdminImages'); - const AdminDir = path.join(ImageDir, Admin.AdminID.toString()); + const AdminDir = path.join(ImageDir, Admin.toString()); // if the path doesn't exist, create it try { @@ -950,10 +301,8 @@ function CreateImage(root, imgname, email, files) { // remove the old dockerfiles and root folder for the new one else { try { - // get all of the files const oldfiles = fs.readdirSync(AdminDir); - // loop through all the files for (var i=0; i < oldfiles.length; i++) { const filepath = path.join(AdminDir,oldfiles[i]); @@ -974,24 +323,20 @@ function CreateImage(root, imgname, email, files) { } catch (err) { console.error(err); } - // get the dockerfile extension let name = imgname; imgname = imgname + '.dockerfile'; - // create the filepath const imagefile = path.join(AdminDir,imgname); - // get all the required image content onto the file first RunCommand('FROM ubuntu:latest\r\nWORKDIR /.\r\nCMD ["bin/bash"]\r\n'); - // start getting contents of files and put into dockerfile await getContents(root,AdminDir, files); RunCommand('COPY Root /. \r\n'); // create dockerfile into an image try { - exec(`cd AdminImages/${Admin.AdminID} && docker build -f ${imgname} -t ${name} .`, { encoding: 'utf-8' }); + exec(`cd AdminImages/${Admin} && docker build -f ${imgname} -t ${name} .`, { encoding: 'utf-8' }); } catch (err) { console.error(err.message); } @@ -1015,7 +360,6 @@ function CreateImage(root, imgname, email, files) { // node is a file else { - let file = null; // get the correct file @@ -1026,8 +370,6 @@ function CreateImage(root, imgname, email, files) { } }); } - - const newfilepath = filepath + '/' + node.name; // not a file from drop box @@ -1041,9 +383,7 @@ function CreateImage(root, imgname, email, files) { const buffer = Buffer.from(file.buffer); await fs.promises.writeFile(newfilepath, buffer); console.log(newfilepath); - } - } } // run a command into dockerfile @@ -1061,16 +401,14 @@ function CreateImage(root, imgname, email, files) { } // Hashing the flag for the user -function getFlagHash(email, flagID) { +export function getFlagHash(email, flagID) { const hash = crypto.createHash('sha256').update(email + flagID).digest('hex'); let digithash = hash.substring(0, 8); const flag = 'NMUCTF${' + digithash + '}'; return flag; } - - -function getPracFlagHash() { +export function getPracFlagHash() { const hash = crypto.createHash('sha256').update(email + flagID).digest('hex'); let digithash = hash.substring(0, 8); for (let i=0; i < 8; i++) { @@ -1081,13 +419,13 @@ function getPracFlagHash() { return flag; } -async function placeFlag(messagestring, container, image){ +export async function placeFlag(messagestring, container, image){ try{ console.log(image); const flag = await getFlagByImage(image); if (image.ActiveFlag === 'ubuntu') return; // return if no flag so ubuntu const FlagHash = getFlagHash(messagestring, flag.FlagID); - console.log("The flag is", flag); + console.log("The flag is", flag.Name); console.log("The file path is", flag.Path); const containerInfo = await container.inspect(); if (!containerInfo.State.Running){ @@ -1125,19 +463,6 @@ async function placeFlag(messagestring, container, image){ Server Start ******************************************************************** */ -/*const io = socketIo.listen(ioport, { - path: '/socket.io', -})*/ - -/*io.on('connection', (socket) => { - console.log('****** Socket.IO Connection Made *****'); - socket.on('enterContestPage', () => { - socket.emit('notification', { message: 'Welcome to the contest!' }); - }); - socket.on('disconnect', () => { - console.log('A user disconnected'); - }) -}); */ // start server on port server.listen(port, ip, () => {