DEV Community

Cover image for Fake C++ Compiler with Node.js - Server - Part 2
Gurigraphics
Gurigraphics

Posted on

Fake C++ Compiler with Node.js - Server - Part 2

C++

Let's make it find the entrypoint and endpoint automatically.

1) Create data.txt with these symbols at the beginning and at the end

<?? hello world ??> 
Enter fullscreen mode Exit fullscreen mode

2) Generate resources.res
3) Generate main.exe.

Server

1) Start

mkdir nodecpp cd nodecpp npm init -y npm i express express-fileupload npm i cors fs path buffer-indexof 
Enter fullscreen mode Exit fullscreen mode

2) path_join.js

const path = require('path') const path_join = function( file, folder ){ if( folder ) return path.join(__dirname, `/${folder}/${ file }`) return path.join(__dirname, `/${ file }`) } module.exports = path_join; 
Enter fullscreen mode Exit fullscreen mode

3) server.js

var cors = require('cors') const path = require('path') const express = require('express') const fileUpload = require('express-fileupload') const app = express() const port = 8000 var corsOptions = { origin: '*', optionsSuccessStatus: 200 } app.use(fileUpload()) app.use(express.static(__dirname + '/www')); var router_home = require("./routes/home") var router_uploads = require("./routes/uploads") var router_downloads = require("./routes/downloads") app.use("/", router_home) app.use("/uploads", router_uploads) app.use("/downloads", router_downloads) app.listen(port, () => { console.log(`Server listening on port ${port}`) }) 
Enter fullscreen mode Exit fullscreen mode

Routes

4) Generate routes folder

mkdir routes 
Enter fullscreen mode Exit fullscreen mode

5) routes/home.js

const express = require("express") const router = express.Router() const controller_home = require("../controllers/home") router.get("/", controller_home.index); module.exports = router; 
Enter fullscreen mode Exit fullscreen mode

6) routes/uploads.js

const express = require("express") const router = express.Router() const controller_uploads = require("../controllers/uploads") router.post("/", controller_uploads.uploadFile, controller_uploads.upload_txt, controller_uploads.upload_exe) module.exports = router 
Enter fullscreen mode Exit fullscreen mode

7) routes/downloads.js

const express = require("express") const router = express.Router() const controller_downloads = require("../controllers/downloads") router.get("/", controller_downloads.getInfo); router.get("/:filename", controller_downloads.getFile); module.exports = router; 
Enter fullscreen mode Exit fullscreen mode

Controllers

Generate controllers folder

mkdir controllers 
Enter fullscreen mode Exit fullscreen mode

8) controllers/home.js

const path_join = require('../path_join') exports.index = async function (req, res, next) { res.sendFile( path_join( "www/index.html" ) ) } 
Enter fullscreen mode Exit fullscreen mode

9) controllers/uploads.js

var service_uploads = require('../services/uploads') var service_compiler = require('../services/compiler') exports.uploadFile = async function ( req, res, next ){ if( req.files && Object.keys(req.files).length !== 0 ){ const uploadedFile = req.files.uploadFile const filename = uploadedFile.name if( !uploadedFile.name.includes(".exe") && !uploadedFile.name.includes(".txt") ){ return res.status(500).json({ error: 'Only EXE or TXT file are accepted' }) } next() }else{ res.status(400).json({ error: 'No file name' }) } } exports.upload_txt = async function ( req, res, next ){ const uploadedFile = req.files.uploadFile const filename = uploadedFile.name if( uploadedFile.name.includes(".exe") ){ next() }else{ try{ service_uploads.uploadFile(uploadedFile, uploadedFile.name, function( err ){ if( err ){ console.log(err); res.status(404).json({ error: 'No such file or directory' }) }else{ res.status(200).json({ ok: 'TXT received!' }) } }) }catch( err ){ console.log( err ) res.status(500).json({ error: 'Server upload file error' }) } } } exports.upload_exe = async function ( req, res, next ){ const uploadedFile = req.files.uploadFile const filename = uploadedFile.name const new_filename = "new_"+filename try{ service_uploads.uploadFile(uploadedFile, uploadedFile.name, function( err ){ if( err ){ console.log(err); res.status(404).json({ error: 'No such file or directory' }) }else{ var result = service_compiler.compile( filename, new_filename ) if( result == "ok" ){ res.redirect(`downloads?filename=${new_filename}`) //res.redirect(`downloads/${new_filename}`) }else{ res.status(404).json({ error: result }) } } }) }catch( err ){ console.log( err ) res.status(500).json({ error: 'Server upload file error' }) } } 
Enter fullscreen mode Exit fullscreen mode

10) controllers/downloads.js

var service_downloads = require('../services/downloads') exports.getInfo = async function ( req, res, next ){ if( req.query.filename ){ try{ var download_info = service_downloads.getInfo( req ) res.json( download_info ) }catch( err ){ console.log( err ) res.status(500).json({ error: 'Server info file error' }) } }else{ res.status(400).send("No file name") } } exports.getFile = async function ( req, res, next ){ if( req.params.filename ){ try{ service_downloads.getFile( req.params.filename, res, function( err ){ if( err ){ console.log(err); res.status(404).json({ error: 'No such file or directory' }) } }) }catch( err ){ console.log( err ) res.status(500).json({ error: 'Server download file error' }) } }else{ res.status(400).json({ error: 'No file name' }) } } 
Enter fullscreen mode Exit fullscreen mode

Services

Generate services folder

mkdir services 
Enter fullscreen mode Exit fullscreen mode

11) services/uploads.js

const path_join = require('../path_join') exports.uploadFile = function( uploadedFile, filename, callback ) { var uploadPath = path_join(filename, "uploads") uploadedFile.mv(uploadPath, async function (err) { if( err ){ console.log(err); callback("Error uploading file"); }else{ callback(null); // No error } }) } 
Enter fullscreen mode Exit fullscreen mode

12) services/downloads.js

const path_join = require('../path_join') exports.getInfo = function( req ){ var folder = "downloads"; var host = req.get('host') var protocol = req.protocol var filename = req.query.filename var download_link = `${protocol}://${host}/${folder}/${filename}`; return { filename: filename, download_link: download_link } } exports.getFile = function( filename, res, callback ) { var file_path = path_join( filename, "uploads" ) res.download( file_path, function( err ) { if( err ){ console.log(err); callback("Error download file"); }else{ callback(null); // No error } }) } 
Enter fullscreen mode Exit fullscreen mode

13) services/compiler.js

var path_join = require('../path_join') var slicer = require('./compiler/slicer') const getIndex = require('./compiler/getIndex'); var merge3binary = require('./compiler/merge3binary') var replaceBinaryText = require('./compiler/replaceBinaryText') exports.compile = function( filename, new_filename ){ var folder = "uploads" var input_path = path_join( filename, folder ) var output_path = path_join( new_filename, folder ) var header_path = path_join( "main_header.exe", folder ) var middle_path = path_join( "main_middle.exe", folder ) var footer_path = path_join( "main_footer.exe", folder ) var data_path = path_join( "data.txt", folder ) var new_path = path_join( "main_middle_updated.exe", folder ) var indexes = getIndex( input_path ) if( indexes.error ){ return indexes.error } var adress_start = indexes[0] var adress_end = indexes[1] // -------- Generate 3 slices slicer( input_path, header_path, "0x00000", adress_start) slicer( input_path, middle_path, adress_start, adress_end) slicer( input_path, footer_path, adress_end, "end") // -------- Update resources region replaceBinaryText( data_path, middle_path, new_path ) // Merge 3 binary merge3binary(header_path, new_path, footer_path, output_path) return "ok" } 
Enter fullscreen mode Exit fullscreen mode

Compiler

Generate compiler folder inside services

mkdir compiler 
Enter fullscreen mode Exit fullscreen mode

14) compiler/getIndex.js

const fs = require('fs'); const BufferIndexOf = require('buffer-indexof'); const getIndex = function( exe_path ){ const input_data = fs.readFileSync( exe_path ) const buffer = Buffer.from( input_data ) const startString = Buffer.from('<??', 'utf-8') const endString = Buffer.from('??>', 'utf-8') const start = BufferIndexOf(buffer, startString) const endSize = BufferIndexOf(buffer, endString, start + startString.length) const end = endSize + endString.length const entryPoint = start.toString(16) const endPoint = end.toString(16) if (start === -1 || end === -1) { return { error: "<?? and ??> not found" } console.log("<?? and ??> not found") } else { console.log("Start:"+entryPoint) console.log("End:"+endPoint) return [entryPoint, endPoint] } } module.exports = getIndex; 
Enter fullscreen mode Exit fullscreen mode

15) compiler/slicer.js

const fs = require('fs') const slicer = function( exe_path, result_path, entry_start, entry_end ){ var file_data; // Set positions const file_start = parseInt( entry_start, 16 ); const file_end = parseInt( entry_end, 16 ); // Get exe const input_data = fs.readFileSync( exe_path ); // Slice if( entry_end == "end" ){ file_data = input_data.slice( file_start ) }else{ file_data = input_data.slice( file_start, file_end ) } // Write fs.writeFileSync( result_path, file_data ); console.log('Binary file sucessfull created!'); } module.exports = slicer; 
Enter fullscreen mode Exit fullscreen mode

16) compiler/replaceBinaryText.js

const fs = require('fs') const replaceBinaryText = function( data_path, input_path, output_path ){ // Get bin const exe = fs.readFileSync( input_path ); const min_size = exe.length; // Get text const input_data = fs.readFileSync( data_path ); const data_size = input_data.length; if( data_size > min_size ){ console.log(`File Error. Maximum size is ${min_size}`); }else{ // Fill const padding_buffer = Buffer.alloc(min_size - data_size, 0x00); // Concat const output_buffer = Buffer.concat([input_data, padding_buffer]); // Write fs.writeFileSync(output_path, output_buffer, 'binary'); console.log('Binary file sucessfull created!'); } } module.exports = replaceBinaryText; 
Enter fullscreen mode Exit fullscreen mode

17) compiler/merge3binary.js

const fs = require('fs') const merge3binary = function( header, middle, footer, output_path ){ const header_data = fs.readFileSync( header ); const middle_data = fs.readFileSync( middle ); const footer_data = fs.readFileSync( footer ); const merged_buffer = Buffer.concat([header_data, middle_data, footer_data]); fs.writeFileSync(output_path, merged_buffer, 'binary'); console.log('Binary file sucessfull created!'); } module.exports = merge3binary; 
Enter fullscreen mode Exit fullscreen mode

Compiler

Generate folders: uploads and www

mkdir uploads mkdir www 
Enter fullscreen mode Exit fullscreen mode

18) www/index.html

<!DOCTYPE html> <html lang='en'> <head> <meta name='viewport' content='width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no'> <meta charset='utf-8'> <title>Fake Compiler C++</title> <link rel='stylesheet' src='style.css'> </head> <body> <div id='root'> <h1>Fake Compiler C++</h1> <form id="txt" method="post" enctype="multipart/form-data" action="/uploads"> <input type="hidden" name="msgtype" value="2"/> <input type="file" name="uploadFile" accept=".txt"/> <button type="submit" value="Upload" >Browse File</button> </form> </div> <script type='javascript' src='main.js'></script> </body> </html> 
Enter fullscreen mode Exit fullscreen mode

19) Run

node server.js 
Enter fullscreen mode Exit fullscreen mode
# Download fileInfo http://localhost:8000/downloads?filename=new_main.exe # Download file http://localhost:8000/downloads/new_main.exe # Post file var post_txt = async() => { const formData = new FormData(txt); try { const response = await fetch('/uploads', { method: 'POST', body: formData }); const data = await response.json(); console.log(data); } catch (error) { console.error(error); } } 
Enter fullscreen mode Exit fullscreen mode

20) Demo

Fake C++ Compiler with Node.js - Frontend - Part 3

https://dev.to/gurigraphics/fake-c-compiler-with-nodejs-frontend-part-3-1m18

Top comments (0)