/* * Copyright (C) 2021 Thomas Van Acker * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with * this program. If not, see . * * This project is hosted on https://git.bitscuit.be/bitscuit/Fawkes * */ // Imports const http = require("http"); const url = require("url"); const fs = require("fs"); const util = require("util"); const crypto = require("crypto"); // Vars const hostname = "192.168.0.128"; // Enter your local IP address here const port = 8001; // Enter a port number here var files = {}; // Create HTTP server const server = http.createServer((req, res) => { // Parse url const requrl = url.parse(req.url); var reqpath = requrl.pathname; if(reqpath == "/") reqpath = "/index.html"; // Respond to requests try{ // Return requested page res.statusCode = 200; res.write(fs.readFileSync("html"+reqpath)); res.end(); }catch(error){ // 404 if page not found res.statusCode = 404; res.setHeader("Content-Type", "text/plain"); res.end("404 - Page Not Found"); } }); // Create socket.io server const io = require("socket.io")(server); // Can only be done when server is created io.on("connection", (socket) => { console.log("New user connected!"); // Give user unique ID var userId = sha256("USER"+rand(0,9999999)+"TIME"+Date.now()).substr(0, 10); console.log("userId = "+userId); // Init directory structure fs.mkdirSync("fawkes/files/"+userId); // Init socket listeners // Disconnect socket.on("disconnect", () => { console.log(userId+": disconnect"); // Remove all files from this user fs.rmSync("fawkes/files/"+userId, {recursive: true}); }); // File upload socket.on("FILE_START", (data) => { console.log(userId+": file upload ("+data.name+", "+data.length+" bytes)"); // Check length if(data.length > 20000000){ console.log(userId+": file too large (data.length = "+data.length+")"); socket.emit("FILE_ERROR", {name:data.name, error:"File too large. Max size = 20MB"}); return; } // Check if exists if((userId+data.name) in files){ console.log(userId+": file already exists (data.name = "+data.name+")"); socket.emit("FILE_ERROR", {name:data.name, error:"File had already been uploaded."}); return; } // Create file var name = data.name; var path = "fawkes/files/"+userId+"/"+name; var file = { length: data.length, name: data.name, path: path, numSegments: data.length/100000 + 1, nextSegment: 0 }; files[userId+data.name] = file; // Ask client to begin upload socket.emit("FILE_ACK", {name:file.name, nextSegment:file.nextSegment, numSegments:file.numSegments}); }); // File contents upload socket.on("FILE_DATA", (data) => { console.log(userId+": file data ("+data.name+", segment "+data.segment+", "+data.data.length+" bytes)"); // Check if file exists if(!((userId+data.name) in files)){ console.log(userId+": received segment for unknown file (data.name = "+data.name+")"); socket.emit("FILE_ERROR", {name:data.name, error:"Received segment for unknown file."}); return; } // Get file var file = files[userId+data.name]; // Check size if(data.data.length > 100000){ console.log(userId+": segment too large (data.name = "+data.name+", data.data.length = "+data.data.length+")"); socket.emit("FILE_ERROR", {name:data.name, error:"Segment too large."}); return; } // Check segment number if(data.segment != file.nextSegment || data.segment >= file.numSegments){ console.log(userId+": unexpected segment (data.name = "+data.name+", data.segment = "+data.segment+")"); socket.emit("FILE_ERROR", {name:data.name, error:"Unexpected segment."}); return; } // Write data fs.appendFile(file.path, data.data, 'Binary', function(err){ if(err){ // Error console.log(userId+": couldn't write to file (error = "+err+")"); socket.emit("FILE_ERROR", {name:data.name, error:"Internal server error. Couldn't write to file."}); }else{ file.nextSegment++; if(file.nextSegment < file.numSegments-1){ // Ask for new segment socket.emit("FILE_ACK", {name:file.name, nextSegment:file.nextSegment, numSegments:file.numSegments}); }else{ // When file fully uploaded socket.emit("FILE_DONE", {name:file.name}); } } }); }); }); // Start HTTP server server.listen(port, hostname, () => { console.log("Server running at http://"+hostname+":"+port); }); // Helper methods function rand(min, max){ return Math.floor(Math.random()*(max-min) + min); } function sha256(message){ return crypto.createHash("sha256").update(message).digest("hex"); }