|
|
|
/*
|
|
|
|
********************************************************************
|
|
|
|
Alex Miller
|
|
|
|
Jordan Latimer
|
|
|
|
|
|
|
|
CTF Server Code
|
|
|
|
********************************************************************
|
|
|
|
*/
|
|
|
|
|
|
|
|
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 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';
|
|
|
|
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());
|
|
|
|
app.use(express.urlencoded({ extended: true }));
|
|
|
|
app.use(cors());
|
|
|
|
|
|
|
|
const storage = multer.memoryStorage();
|
|
|
|
const upload = multer({ storage });
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
********************************************************************
|
|
|
|
On Connection
|
|
|
|
********************************************************************
|
|
|
|
*/
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
console.log("MessageString:", messagestring);
|
|
|
|
// if it's an email, create the container
|
|
|
|
if(messagestring !== undefined && IsEmail(messagestring)) {
|
|
|
|
try {
|
|
|
|
const container = await CheckContainer(messagestring);
|
|
|
|
getActiveFlagImage(messagestring).then((image) => {
|
|
|
|
placeFlag(messagestring, container, image);
|
|
|
|
});
|
|
|
|
|
|
|
|
container.exec({
|
|
|
|
Cmd: ['/bin/bash'],
|
|
|
|
AttachStdin: true,
|
|
|
|
AttachStdout: true,
|
|
|
|
AttachStderr: true,
|
|
|
|
Tty: true,
|
|
|
|
}, (err, exec) => {
|
|
|
|
if (err) {
|
|
|
|
return ws.send('Error: ' + err.message);
|
|
|
|
}
|
|
|
|
|
|
|
|
// take over the container via terminal in contest pages
|
|
|
|
exec.start({ hijack: true, stdin: true, stdout: true, stderr: true}, (err, stream) => {
|
|
|
|
|
|
|
|
// used to get rid of header from docker buffer
|
|
|
|
const cleanser = new DockerStreamCleanser();
|
|
|
|
|
|
|
|
if (err) {
|
|
|
|
return ws.send('Error: ' + err.message);
|
|
|
|
}
|
|
|
|
|
|
|
|
// both docker container sending and terminal recieving
|
|
|
|
stream.pipe(cleanser).on('data', (data) => {
|
|
|
|
ws.send(data.toString());
|
|
|
|
});
|
|
|
|
|
|
|
|
stream.on('error', (err) => {
|
|
|
|
console.log('stream error: ' + err);
|
|
|
|
});
|
|
|
|
|
|
|
|
// from terminal to docker container
|
|
|
|
ws.on('message', (message) => {
|
|
|
|
stream.write(message.toString());
|
|
|
|
});
|
|
|
|
|
|
|
|
// connection closes
|
|
|
|
ws.on('close', async () => {
|
|
|
|
try { // try deleting container
|
|
|
|
clearActiveFlag(messagestring);
|
|
|
|
console.log('Deleting Container: ' + container.id);
|
|
|
|
await container.kill();
|
|
|
|
await container.remove({ force: true });
|
|
|
|
console.log('----- Container: ' + container.id + ' has been deleted -----');
|
|
|
|
} catch (err) { // error catching
|
|
|
|
if (err.statusCode === 409) {
|
|
|
|
const cont = docker.getContainer(container.id);
|
|
|
|
cont.start();
|
|
|
|
cont.kill();
|
|
|
|
cont.remove({ force: true });
|
|
|
|
}
|
|
|
|
else if (err.statusCode === 404) console.log('404');
|
|
|
|
else console.error(err);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
} catch(err){
|
|
|
|
console.error('Error handling connection:', err.message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
********************************************************************
|
|
|
|
Get Requests
|
|
|
|
********************************************************************
|
|
|
|
*/
|
|
|
|
|
|
|
|
//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')
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
********************************************************************
|
|
|
|
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
|
|
|
|
********************************************************************
|
|
|
|
*/
|
|
|
|
|
|
|
|
// 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) => {
|
|
|
|
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 });
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
// get all the info for leaderboards
|
|
|
|
app.post('/FillLeaderboard', (req,res) => {
|
|
|
|
const { email, contest } = req.body;
|
|
|
|
return AdminorUser(email).then((AoU) => {
|
|
|
|
if (AoU === 'Admins') {
|
|
|
|
return getAdminID(email).then((Admin) => {
|
|
|
|
return getUsersFromAdmin(Admin.AdminID).then((users) => {
|
|
|
|
return getContestIDFromName(contest).then((contestID) => {
|
|
|
|
return getFlagFromContestID(contestID[0].ContestID).then((flags) => {
|
|
|
|
return getAllSubs().then((subs) => {
|
|
|
|
return res.status(200).json({ users: users, flags: flags, subs: subs, contestID: contestID });
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return getAdminFromUser(email).then((Admin) => {
|
|
|
|
return getUsersFromAdmin(Admin.AdminID).then((users) => {
|
|
|
|
return getContestIDFromName(contest).then((contestID) => {
|
|
|
|
return getFlagFromContestID(contestID[0].ContestID).then((flags) => {
|
|
|
|
return getAllSubs().then((subs) => {
|
|
|
|
return res.status(200).json({ users: users, flags: flags, subs: subs, contestID: contestID });
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
// 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{
|
|
|
|
await CheckContainer(email);
|
|
|
|
res.status(200).json({ message: 'container updated'});
|
|
|
|
} catch(err) {
|
|
|
|
console.error('Error updating container', err.message);
|
|
|
|
res.status(500).json({error: 'Error updating container.'});
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
// 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) => {
|
|
|
|
const query = 'SELECT COUNT(*) AS count FROM Admins WHERE Email = ?';
|
|
|
|
con.query(query, [email], (err,rows) => {
|
|
|
|
if(err) {
|
|
|
|
console.error(err.message);
|
|
|
|
reject(err);
|
|
|
|
}
|
|
|
|
if (rows[0].count > 0){
|
|
|
|
resolve('Admins');
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
resolve('Users');
|
|
|
|
}
|
|
|
|
});
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
********************************************************************
|
|
|
|
*/
|
|
|
|
|
|
|
|
// get the username portion of the email sent over
|
|
|
|
function getUsername(email) {
|
|
|
|
let username = '';
|
|
|
|
for (var i=0; i < email.length-1; i++) {
|
|
|
|
if (email[i] != '@') username += email[i];
|
|
|
|
else {
|
|
|
|
return username;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns true if the string is an email
|
|
|
|
function IsEmail(email) {
|
|
|
|
for (let i=0; i < email.length; i++) {
|
|
|
|
if (email[i] === "@") return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// create an image with the given tree
|
|
|
|
function CreateImage(root, imgname, email, files) {
|
|
|
|
|
|
|
|
// get the Admin for database and file path
|
|
|
|
getAdminID(email).then(async (Admin) => {
|
|
|
|
|
|
|
|
// 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());
|
|
|
|
|
|
|
|
// if the path doesn't exist, create it
|
|
|
|
try {
|
|
|
|
if (!fs.existsSync(AdminDir)) {
|
|
|
|
fs.mkdirSync(AdminDir);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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]);
|
|
|
|
const stat = fs.statSync(filepath);
|
|
|
|
|
|
|
|
// delete depending on if its a folder or file
|
|
|
|
if (stat.isFile()) {
|
|
|
|
fs.unlinkSync(filepath);
|
|
|
|
}
|
|
|
|
else if (stat.isDirectory()) {
|
|
|
|
fs.rmdirSync(filepath, { recursive: true });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (err) {
|
|
|
|
console.error(err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} 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' });
|
|
|
|
} catch (err) {
|
|
|
|
console.error(err.message);
|
|
|
|
}
|
|
|
|
|
|
|
|
// get all the contents of the files and create the file system
|
|
|
|
async function getContents(node, filepath, files) {
|
|
|
|
|
|
|
|
// create the current folder if folder
|
|
|
|
if (node.directory === true) {
|
|
|
|
|
|
|
|
fs.mkdirSync(filepath+ '/' + node.name);
|
|
|
|
filepath = path.join(filepath,node.name);
|
|
|
|
|
|
|
|
// if directory has children
|
|
|
|
if (node.children.length > 0) {
|
|
|
|
for (var i=0; i < node.children.length; i++) {
|
|
|
|
getContents(node.children[i], filepath, files);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// node is a file
|
|
|
|
else {
|
|
|
|
|
|
|
|
let file = null;
|
|
|
|
|
|
|
|
// get the correct file
|
|
|
|
if (files != null || files != undefined) {
|
|
|
|
files.forEach((File) => {
|
|
|
|
if (File.originalname === node.name) {
|
|
|
|
file = File;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const newfilepath = filepath + '/' + node.name;
|
|
|
|
|
|
|
|
// not a file from drop box
|
|
|
|
if (file === null) {
|
|
|
|
file = new File([node.content], node.name, {type: 'text/plain', mode: 0o777 });
|
|
|
|
fs.writeFileSync(newfilepath, node.contents);
|
|
|
|
}
|
|
|
|
|
|
|
|
// file from dropbox
|
|
|
|
else {
|
|
|
|
const buffer = Buffer.from(file.buffer);
|
|
|
|
await fs.promises.writeFile(newfilepath, buffer);
|
|
|
|
console.log(newfilepath);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// run a command into dockerfile
|
|
|
|
function RunCommand(command) {
|
|
|
|
fs.appendFileSync(imagefile,
|
|
|
|
command,
|
|
|
|
(err) => {
|
|
|
|
if (err) {
|
|
|
|
console.error('Error Creating DockerFile: ',err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// Hashing the flag for the user
|
|
|
|
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() {
|
|
|
|
const hash = crypto.createHash('sha256').update(email + flagID).digest('hex');
|
|
|
|
let digithash = hash.substring(0, 8);
|
|
|
|
for (let i=0; i < 8; i++) {
|
|
|
|
let j = crypto.randomInt(0,20);
|
|
|
|
digithash += hash[j];
|
|
|
|
}
|
|
|
|
const flag = 'NMUCTF${' + digithash + '}';
|
|
|
|
return flag;
|
|
|
|
}
|
|
|
|
|
|
|
|
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 file path is", flag.Path);
|
|
|
|
const containerInfo = await container.inspect();
|
|
|
|
if (!containerInfo.State.Running){
|
|
|
|
console.error('Container is not running');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const exec = await container.exec({
|
|
|
|
Cmd: ['/bin/bash', '-c', `sed -i 's|\\[FLAG\\]|${FlagHash}|g' ${flag.Path}`],
|
|
|
|
});
|
|
|
|
|
|
|
|
exec.start({hijack: true, stdin: true, stdout: true, stderr: true}, (err, stream) => {
|
|
|
|
if(err){
|
|
|
|
console.log('Exec error:', err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
stream.on('data', (data) => {
|
|
|
|
console.log('Exec Output:', data.toString());
|
|
|
|
});
|
|
|
|
stream.on('error', (err) => {
|
|
|
|
console.error('Stream error:', err);
|
|
|
|
});
|
|
|
|
// Wait until the exec process finishes
|
|
|
|
stream.on('end', () => {
|
|
|
|
console.log("Exec process completed.");
|
|
|
|
});
|
|
|
|
//await new Promise((resolve) => stream.on('end', resolve));
|
|
|
|
});
|
|
|
|
} catch(err){
|
|
|
|
console.error('Error in placeFlag:', err.message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
********************************************************************
|
|
|
|
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, () => {
|
|
|
|
console.log('Server started at http://' + ip + ":" + port);
|
|
|
|
});
|