Compare commits

..

3 Commits

@ -183,7 +183,7 @@ export async function setNewFlag(flag: Flag, el: ElementRef, elements: any, ts:
const email = getEmail(); const email = getEmail();
const data = { FlagImage: flag.Image, email: email }; const data = { FlagImage: flag.Image, email: email };
const res = await fetch('api/setNewActiveFlag', { const res = await fetch('api/flags/setNewActiveFlag', {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type' : 'application/json' 'Content-Type' : 'application/json'
@ -279,14 +279,14 @@ async function checkSubmission(isPractice: boolean, el: ElementRef, socket: Sock
} }
let res, result; let res, result;
if(!isPractice){ if(!isPractice){
res = await fetch('api/checkFlagSubmission', { res = await fetch('api/submissions/checkFlagSubmission', {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json'}, headers: { 'Content-Type': 'application/json'},
body: JSON.stringify({ email, flagID, submittedFlag }) body: JSON.stringify({ email, flagID, submittedFlag })
}); });
} }
else{ else{
res = await fetch('api/checkPracSubmission', { res = await fetch('api/submissions/checkPracSubmission', {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json'}, headers: { 'Content-Type': 'application/json'},
body: JSON.stringify({ email, flagID, submittedFlag }) body: JSON.stringify({ email, flagID, submittedFlag })

@ -20,7 +20,7 @@ export class AddContestComponent {
const isActive = 0; const isActive = 0;
console.log("EMAIL IS:", this.getEmail()) console.log("EMAIL IS:", this.getEmail())
const data = {Name: name, IsActive: isActive, email: this.getEmail(), Desc: desc}; 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', method: 'POST',
headers: { headers: {
'Content-Type' : 'application/json' 'Content-Type' : 'application/json'

@ -50,8 +50,9 @@
<!-- image of the flag to create container --> <!-- image of the flag to create container -->
<label> Image: </label> <label> Image: </label>
<select id="Images"> <select id="Images" [(ngModel)]="selectedImage">
<option> ubuntu </option> <option> ubuntu </option>
<option *ngFor="let image of allImages" [value] ="image.Name">{{image.Name}}</option>
</select> </select>
<br><br> <br><br>

@ -1,16 +1,26 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { gotoPage } from '../Helper/Helpers'; import { gotoPage, getEmail } from '../Helper/Helpers';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { ModifyContestService } from '../modify-contest/modify-contest.service';
import { Image } from '../models/image.model';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
@Component({ @Component({
selector: 'app-add-flag', selector: 'app-add-flag',
imports: [], imports: [CommonModule, FormsModule],
templateUrl: './add-flag.component.html', templateUrl: './add-flag.component.html',
styleUrl: './add-flag.component.css' styleUrl: './add-flag.component.css'
}) })
export class AddFlagComponent { export class AddFlagComponent {
constructor(private router: Router){} allImages: Image[] = [];
selectedImage: string = "Select an Image";
constructor(private router: Router, private modifyContestService: ModifyContestService){}
ngOnInit(): void {
this.getImages();
}
// add a flag to a contest // add a flag to a contest
async AddFlag(){ async AddFlag(){
// get contestId from URL // get contestId from URL
@ -38,7 +48,7 @@ export class AddFlagComponent {
// add the flag // 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 || ''}; 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{ try{
const response = await fetch('api/AddFlag', { const response = await fetch('api/flags/AddFlag', {
method: 'POST', method: 'POST',
headers: {'Content-Type': 'application/json',}, headers: {'Content-Type': 'application/json',},
body: JSON.stringify(data) body: JSON.stringify(data)
@ -58,7 +68,21 @@ export class AddFlagComponent {
} }
} }
async getImages(): Promise<void>{
const email = this.getEmail();
try{
const imageData = await this.modifyContestService.getImages(email);
this.allImages = imageData || [];
}catch(error){
console.error('Error loading images');
}
}
navtoPageCI(){ navtoPageCI(){
gotoPage(this.router, '/create-image'); gotoPage(this.router, '/create-image');
} }
getEmail(): string{
return getEmail();
}
} }

@ -36,7 +36,7 @@ export class AddStudentComponent {
if (this.password == this.confirmPassword) { // passwords match if (this.password == this.confirmPassword) { // passwords match
const data = {name: this.Uname, email: this.email, Aemail: Aemail, password: this.password}; 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', method: 'POST',
headers: { headers: {
'Content-Type' : 'application/json' 'Content-Type' : 'application/json'

@ -33,7 +33,6 @@ export class AdminProfileComponent implements OnInit{
this.populateTable(); this.populateTable();
} }
async populateTable(){ async populateTable(){
try{ try{
const email = this.getEmail(); const email = this.getEmail();
@ -54,6 +53,8 @@ export class AdminProfileComponent implements OnInit{
const result = await this.adminProfileService.getContestFlagsSubs(email, this.selectedContest); const result = await this.adminProfileService.getContestFlagsSubs(email, this.selectedContest);
this.flags = result.flags; this.flags = result.flags;
this.subs = result.subs; this.subs = result.subs;
console.log("flags", this.flags);
console.log("Subs", this.subs);
}catch(error){ }catch(error){
console.error('Failed to populate flag table'); console.error('Failed to populate flag table');
} }

@ -281,7 +281,7 @@ export class CreateImageComponent {
formdata.append('data', JSON.stringify(data)); formdata.append('data', JSON.stringify(data));
// send the post request // send the post request
const res = await fetch('api/AddImage', { const res = await fetch('api/images/AddImage', {
method: 'POST', method: 'POST',
body: formdata body: formdata
}); });

@ -25,7 +25,7 @@ export class EditStudentComponent {
if (ps1 == ps2) { // if both passwords are equal, continue if (ps1 == ps2) { // if both passwords are equal, continue
const data = { email: this.emailinput, password: ps1}; const data = { email: this.emailinput, password: ps1};
const res = await fetch('api/UpdateStudent', { const res = await fetch('api/users/UpdateStudent', {
method: "POST", method: "POST",
headers: { headers: {
'Content-Type' : 'application/json' 'Content-Type' : 'application/json'

@ -112,9 +112,13 @@ handlePopupMessage(event: MessageEvent): void {
if (this.selectedContestId !== null) { if (this.selectedContestId !== null) {
try { try {
const email = this.getEmail(); const email = this.getEmail();
await this.modifyContestService.setContestActive(this.selectedContestId, email); const actOrDeact = await this.modifyContestService.setContestActive(this.selectedContestId, email);
this.loadContests(); if(actOrDeact === 1){
console.log('Contest set as active'); this.loadContests();
console.log('Contest set as active');
}
else if(actOrDeact === 0)
this.activeContest = null;
} catch (error) { } catch (error) {
console.error('Error activating contest:', error); console.error('Error activating contest:', error);
} }

@ -9,7 +9,7 @@ export class ModifyContestService {
async getImages(email: string): Promise<any> { async getImages(email: string): Promise<any> {
try { try {
const response = await fetch('api/getImages', { const response = await fetch('api/images/getImages', {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
@ -71,7 +71,7 @@ export class ModifyContestService {
async addContest(data: any): Promise<any> { async addContest(data: any): Promise<any> {
try { try {
const response = await fetch('api/AddContest', { const response = await fetch('api/constests/AddContest', {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
@ -93,7 +93,7 @@ export class ModifyContestService {
// Send a POST request to delete the contest by its name // Send a POST request to delete the contest by its name
let data = {contest: contestId}; let data = {contest: contestId};
await this.deleteFlagsFromContest(contestId); await this.deleteFlagsFromContest(contestId);
let res = await fetch('api/DeleteContest', { let res = await fetch('api/contests/DeleteContest', {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@ -111,7 +111,7 @@ export class ModifyContestService {
async deleteFlagsFromContest(contestId: number): Promise<any> { async deleteFlagsFromContest(contestId: number): Promise<any> {
try { try {
const response = await fetch('api/DeleteFlagsFromContest', { const response = await fetch('api/flags/DeleteFlagsFromContest', {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
@ -131,7 +131,7 @@ export class ModifyContestService {
async AddFlag(data: any): Promise<any> { async AddFlag(data: any): Promise<any> {
try { try {
const response = await fetch('api/AddFlag', { const response = await fetch('api/flags/AddFlag', {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
@ -151,7 +151,7 @@ export class ModifyContestService {
async DeleteFlag(flagId: number): Promise<any> { async DeleteFlag(flagId: number): Promise<any> {
let data = { flag: flagId }; let data = { flag: flagId };
let res = await fetch('api/DeleteFlag', { let res = await fetch('api/flags/DeleteFlag', {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@ -164,7 +164,7 @@ export class ModifyContestService {
const image = flagImage; const image = flagImage;
// set up the container for the image // set up the container for the image
const data = { FlagImage: image, email: Email }; const data = { FlagImage: image, email: Email };
const res = await fetch('/api/setNewActiveFlag', { const res = await fetch('/api/flags/setNewActiveFlag', {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type' : 'application/json' 'Content-Type' : 'application/json'
@ -174,28 +174,50 @@ export class ModifyContestService {
} }
async setContestActive(contestId: number, email: string): Promise<any> { async setContestActive(contestId: number, email: string): Promise<any> {
try { const oldcontestID = await this.getActiveContest(email);
const response = await fetch('api/setContestActive', { if(oldcontestID !== 0 && oldcontestID === contestId){
method: 'POST', try{
headers: { const response = await fetch('api/contests/EndContest', {
'Content-Type': 'application/json' method: 'POST',
}, headers: {
body: JSON.stringify({ contest: contestId, email }) 'Content-Type': 'application/json'
}); },
body: JSON.stringify({contest: oldcontestID, email})
if (!response.ok) { });
throw new Error('Failed to set contest active'); if(!response.ok)
} throw new Error('Failed to end contest');
return await response.json(); await response.json();
} catch (error) { return 0;
console.error('Error setting contest active:', error); }catch(error){
console.error('Error ending contest');
throw error; 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<any> { async deleteImage(imageName: string | undefined): Promise<any> {
try { try {
const response = await fetch('api/DeleteImageReplaceFlags', { const response = await fetch('api/images/DeleteImageReplaceFlags', {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json' 'Content-Type': 'application/json'

@ -1,3 +1 @@
<h1>Thought you could pull a fast one eh?</h1> <h1>You do not have permission to access this page.</h1>
<p>I dont think so</p>
<h2>👎</h2>

File diff suppressed because it is too large Load Diff

@ -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);
}
};

@ -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;

@ -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;

@ -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;

@ -15,6 +15,7 @@
"docker-stream-cleanser": "^1.0.1", "docker-stream-cleanser": "^1.0.1",
"dockerode": "^4.0.4", "dockerode": "^4.0.4",
"express": "^4.21.2", "express": "^4.21.2",
"express-session": "^1.18.1",
"jsonwebtoken": "^9.0.2", "jsonwebtoken": "^9.0.2",
"multer": "^1.4.5-lts.1", "multer": "^1.4.5-lts.1",
"mysql": "^2.18.1", "mysql": "^2.18.1",
@ -1076,6 +1077,55 @@
"url": "https://opencollective.com/express" "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": { "node_modules/express/node_modules/debug": {
"version": "2.6.9", "version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
@ -1952,6 +2002,15 @@
"node": ">= 0.8" "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": { "node_modules/once": {
"version": "1.4.0", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@ -2053,6 +2112,15 @@
"url": "https://github.com/sponsors/ljharb" "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": { "node_modules/range-parser": {
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
@ -2653,6 +2721,18 @@
"integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
"license": "MIT" "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": { "node_modules/undici-types": {
"version": "6.21.0", "version": "6.21.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",

@ -17,6 +17,7 @@
"docker-stream-cleanser": "^1.0.1", "docker-stream-cleanser": "^1.0.1",
"dockerode": "^4.0.4", "dockerode": "^4.0.4",
"express": "^4.21.2", "express": "^4.21.2",
"express-session": "^1.18.1",
"jsonwebtoken": "^9.0.2", "jsonwebtoken": "^9.0.2",
"multer": "^1.4.5-lts.1", "multer": "^1.4.5-lts.1",
"mysql": "^2.18.1", "mysql": "^2.18.1",

@ -1,6 +1,4 @@
import con from '../db/db.js'; import con from '../db/dbconnection.js';
import { Router } from "express";
const router = Router();
// get the Admin foreign key from User table // get the Admin foreign key from User table
export async function getAdminFromUser(email) { export async function getAdminFromUser(email) {
@ -25,9 +23,7 @@ export async function getAdminID(email) {
console.error(err.message); console.error(err.message);
reject(err); reject(err);
} }
resolve(rows[0]); resolve(rows[0].AdminID);
}); });
}); });
} }
export default router;

@ -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);
});
});
}

@ -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);
});
});
}

@ -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);
}
});
}

@ -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);
})
});
}

@ -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);
});
});
}

@ -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;

@ -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;

@ -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;

@ -1,5 +1,5 @@
import { Router } from "express"; import { Router } from "express";
import { getUserByEmail } from '../gets/userQueries.js'; import { getUserByEmail } from '../queries/userQueries.js';
import bcrypt from 'bcrypt'; import bcrypt from 'bcrypt';
const router = Router(); //create a router object to handle routes const router = Router(); //create a router object to handle routes

@ -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;

@ -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;

@ -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 // IP and PORT
const port = 3000; const port = 3000;
const ioport = 3001; const ioport = 3001;
const ip = 'localhost'; const ip = 'localhost';
// imports // 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 path from 'path';
import express from 'express'; import express from 'express';
import http from 'http'; import http from 'http';
import cors from 'cors'; import cors from 'cors';
import crypto from 'crypto'; import crypto from 'crypto';
import fs from 'fs'; import fs from 'fs';
import jwt from 'jsonwebtoken';
import multer from 'multer'; import multer from 'multer';
import Docker from 'dockerode';
import DockerStreamCleanser from 'docker-stream-cleanser'; import DockerStreamCleanser from 'docker-stream-cleanser';
import { WebSocketServer } from 'ws'; import { WebSocketServer } from 'ws';
import { exec } from 'child_process' import { exec } from 'child_process'
import { fileURLToPath } from 'url'; import { fileURLToPath } from 'url';
import { Session } from "express-session";
import { CheckContainer } from "./containers/containers.js";
const __filename = fileURLToPath(import.meta.url); const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename); const __dirname = path.dirname(__filename);
const router = express.Router();
const app = express(); const app = express();
// express stuff // express stuff
app.use(express.static(path.join(__dirname, '/'))); app.use(express.static(path.join(__dirname, '/')));
app.use(express.json()); app.use(express.json());
@ -58,15 +60,12 @@ const upload = multer({ storage });
// start the server with the socket // start the server with the socket
const server = http.createServer(app); const server = http.createServer(app);
//const io = socketIo(server);
const wss = new WebSocketServer({ server }); const wss = new WebSocketServer({ server });
// on connection to the server // on connection to the server
wss.on('connection', async (ws) => { wss.on('connection', async (ws) => {
console.log('***** Connection Made *****'); console.log('***** Connection Made *****');
ws.on('message', async (message) => { ws.on('message', async (message) => {
// get the first message into the socket // get the first message into the socket
let messagestring = Buffer.isBuffer(message) ? message.toString('utf-8') : message; let messagestring = Buffer.isBuffer(message) ? message.toString('utf-8') : message;
messagestring = messagestring.substring(1,messagestring.length-1); messagestring = messagestring.substring(1,messagestring.length-1);
@ -78,7 +77,6 @@ wss.on('connection', async (ws) => {
getActiveFlagImage(messagestring).then((image) => { getActiveFlagImage(messagestring).then((image) => {
placeFlag(messagestring, container, image); placeFlag(messagestring, container, image);
}); });
container.exec({ container.exec({
Cmd: ['/bin/bash'], Cmd: ['/bin/bash'],
AttachStdin: true, AttachStdin: true,
@ -149,344 +147,45 @@ wss.on('connection', async (ws) => {
******************************************************************** ********************************************************************
*/ */
//ROUTES /*app.use(Session({ secret: 'key',
app.use("/login", login); resave: false,
saveUninitialized: false,
cookie: { secure: false, maxAge: 100 * 60 * 60 } //10 minutes
}));*/
app.use('/contests', contestQueries);
app.use('/flags', flagQueries); //ROUTES
app.use("/login", login);
app.use('/users', userQueries);
app.use('/admins', adminQueries); app.use('/contests', contestHandler);
// Admin Contest page app.use('/flags', flagHandler);
app.get('/Admin_Contest', (req, res) => {
res.sendFile(__dirname + '/(A)Contest_Page.html');
});
// User Contest page app.use('/users', userHandler);
app.get('/User_Contest', (req, res) => {
res.sendFile(__dirname + '/contest-page.html');
});
// User menu page app.use('/submissions', submissionHandler);
app.get('/User_Menu', (req, res) => {
res.sendFile(__dirname + '/User_Menu.html');
});
// User Menu Screen app.use('/images', imageHandler);
app.get('/User_Contest', (req, res) => {
res.sendFile(__dirname + '/User_Menu.html');
})
// Admin Modify Contest Screen //app.use('/admins', adminHandler);
app.get('/Admin_Contest', (req, res) => {
res.sendFile(__dirname + '/Modify_Contests.html')
});
/*
********************************************************************
Docker Containers
********************************************************************
*/
// 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
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);
}
};
/* /*
******************************************************************** ********************************************************************
POST Requests for Database POST Requests for Database
******************************************************************** ********************************************************************
*/ */
// 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 // 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; const { email, contest } = req.body;
// get all of the contests // get all of the contests
return getContestIDFromNameAdminID(email,contest).then((contestID) => { return getContestIDFromNameAdminID(email,contest).then(async (contestID) => {
return getFlagFromContestID(contestID.ContestID).then((flags) => { console.log(contestID);
return getAllSubs().then((subs) => { const flags = await getFlagFromContestID(contestID);
return res.status(200).json({ flags: flags, subs: subs }); const subs = await getAllSubs();
}); 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 });
}); });
}); });
@ -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) => { app.post('/updateContainer/:email', async(req, res) => {
const { email } = req.params; const { email } = req.params;
try{ try{
@ -612,192 +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 {
execSync(`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 whether the email belongs to an admin or a user // get whether the email belongs to an admin or a user
export async function AdminorUser(email) { export async function AdminorUser(email) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -817,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 Functions
@ -895,7 +261,7 @@ async function getAllSubs() {
*/ */
// get the username portion of the email sent over // get the username portion of the email sent over
function getUsername(email) { export function getUsername(email) {
let username = ''; let username = '';
for (var i=0; i < email.length-1; i++) { for (var i=0; i < email.length-1; i++) {
if (email[i] != '@') username += email[i]; if (email[i] != '@') username += email[i];
@ -906,7 +272,7 @@ function getUsername(email) {
} }
// Returns true if the string is an email // Returns true if the string is an email
function IsEmail(email) { export function IsEmail(email) {
for (let i=0; i < email.length; i++) { for (let i=0; i < email.length; i++) {
if (email[i] === "@") return true; if (email[i] === "@") return true;
} }
@ -914,7 +280,7 @@ function IsEmail(email) {
} }
// create an image with the given tree // 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 // get the Admin for database and file path
getAdminID(email).then(async (Admin) => { getAdminID(email).then(async (Admin) => {
@ -922,10 +288,9 @@ function CreateImage(root, imgname, email, files) {
// add the image to the database // add the image to the database
AddImage(Admin,imgname); AddImage(Admin,imgname);
// go into directory and check if folder exists // go into directory and check if folder exists
const ImageDir = path.join(__dirname, 'AdminImages'); 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 // if the path doesn't exist, create it
try { try {
@ -936,10 +301,8 @@ function CreateImage(root, imgname, email, files) {
// remove the old dockerfiles and root folder for the new one // remove the old dockerfiles and root folder for the new one
else { else {
try { try {
// get all of the files // get all of the files
const oldfiles = fs.readdirSync(AdminDir); const oldfiles = fs.readdirSync(AdminDir);
// loop through all the files // loop through all the files
for (var i=0; i < oldfiles.length; i++) { for (var i=0; i < oldfiles.length; i++) {
const filepath = path.join(AdminDir,oldfiles[i]); const filepath = path.join(AdminDir,oldfiles[i]);
@ -960,24 +323,20 @@ function CreateImage(root, imgname, email, files) {
} catch (err) { } catch (err) {
console.error(err); console.error(err);
} }
// get the dockerfile extension // get the dockerfile extension
let name = imgname; let name = imgname;
imgname = imgname + '.dockerfile'; imgname = imgname + '.dockerfile';
// create the filepath // create the filepath
const imagefile = path.join(AdminDir,imgname); const imagefile = path.join(AdminDir,imgname);
// get all the required image content onto the file first // get all the required image content onto the file first
RunCommand('FROM ubuntu:latest\r\nWORKDIR /.\r\nCMD ["bin/bash"]\r\n'); RunCommand('FROM ubuntu:latest\r\nWORKDIR /.\r\nCMD ["bin/bash"]\r\n');
// start getting contents of files and put into dockerfile // start getting contents of files and put into dockerfile
await getContents(root,AdminDir, files); await getContents(root,AdminDir, files);
RunCommand('COPY Root /. \r\n'); RunCommand('COPY Root /. \r\n');
// create dockerfile into an image // create dockerfile into an image
try { 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) { } catch (err) {
console.error(err.message); console.error(err.message);
} }
@ -1001,7 +360,6 @@ function CreateImage(root, imgname, email, files) {
// node is a file // node is a file
else { else {
let file = null; let file = null;
// get the correct file // get the correct file
@ -1012,8 +370,6 @@ function CreateImage(root, imgname, email, files) {
} }
}); });
} }
const newfilepath = filepath + '/' + node.name; const newfilepath = filepath + '/' + node.name;
// not a file from drop box // not a file from drop box
@ -1027,9 +383,7 @@ function CreateImage(root, imgname, email, files) {
const buffer = Buffer.from(file.buffer); const buffer = Buffer.from(file.buffer);
await fs.promises.writeFile(newfilepath, buffer); await fs.promises.writeFile(newfilepath, buffer);
console.log(newfilepath); console.log(newfilepath);
} }
} }
} }
// run a command into dockerfile // run a command into dockerfile
@ -1047,16 +401,14 @@ function CreateImage(root, imgname, email, files) {
} }
// Hashing the flag for the user // 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'); const hash = crypto.createHash('sha256').update(email + flagID).digest('hex');
let digithash = hash.substring(0, 8); let digithash = hash.substring(0, 8);
const flag = 'NMUCTF${' + digithash + '}'; const flag = 'NMUCTF${' + digithash + '}';
return flag; return flag;
} }
export function getPracFlagHash() {
function getPracFlagHash() {
const hash = crypto.createHash('sha256').update(email + flagID).digest('hex'); const hash = crypto.createHash('sha256').update(email + flagID).digest('hex');
let digithash = hash.substring(0, 8); let digithash = hash.substring(0, 8);
for (let i=0; i < 8; i++) { for (let i=0; i < 8; i++) {
@ -1067,13 +419,13 @@ function getPracFlagHash() {
return flag; return flag;
} }
async function placeFlag(messagestring, container, image){ export async function placeFlag(messagestring, container, image){
try{ try{
console.log(image); console.log(image);
const flag = await getFlagByImage(image); const flag = await getFlagByImage(image);
if (image.ActiveFlag === 'ubuntu') return; // return if no flag so ubuntu if (image.ActiveFlag === 'ubuntu') return; // return if no flag so ubuntu
const FlagHash = getFlagHash(messagestring, flag.FlagID); 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); console.log("The file path is", flag.Path);
const containerInfo = await container.inspect(); const containerInfo = await container.inspect();
if (!containerInfo.State.Running){ if (!containerInfo.State.Running){
@ -1081,7 +433,7 @@ async function placeFlag(messagestring, container, image){
return; return;
} }
const exec = await container.exec({ const exec = await container.exec({
Cmd: ['/bin/bash', '-c', `echo '${FlagHash}' > ${flag.Path}`], Cmd: ['/bin/bash', '-c', `sed -i 's|\\[FLAG\\]|${FlagHash}|g' ${flag.Path}`],
}); });
exec.start({hijack: true, stdin: true, stdout: true, stderr: true}, (err, stream) => { exec.start({hijack: true, stdin: true, stdout: true, stderr: true}, (err, stream) => {
@ -1111,19 +463,6 @@ async function placeFlag(messagestring, container, image){
Server Start 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 // start server on port
server.listen(port, ip, () => { server.listen(port, ip, () => {

Loading…
Cancel
Save