Mini Tor implementation (âCLI only anonymous networkâ)
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
3
down vote
favorite
The goal of my project is to build a mini "anonymous" network (like Tor is) (command-line only
) using Node.js and frameworks (socket.io / axios / express). A network where I can download files (HTML etc) anonymously. I have central server
and nodes (clients
). At start each client connects to central server (using socket.io) and server appends it to the list hosts
. Each minute client asks server for latest list of alive nodes.
I came here because I did my best and I cannot see more bugs / errors / flaws. Also, I am not good at security and only on my way to learning deep.
I have some questions and I will be grateful if you advise how to improve my code:
- What can be improved and how?
- What about security?
- My node-chain isn't that good now. How I can make it longer (right now I have to set 1 minute timer and start nodes at different time but it is bad; in- fact that if some node will die in the middle, my code would be ruined, so I am looking for real-time long (at least 3 nodes) chain)
- Right now I am receiving the answer as HTML in my console. Is it possible to do so that if node localhost:4500 sends request I can see the answer as website at localhost:4500?
Maybe my central server
should create graf of clients
where each client
(node) will have 3 (strict) neighbor nodes, but how to implement that? (image visualisation below!)
My code is fully working and you can see it below with some rules that my project has.
URL (file) download request
If the node initiates this query itself, it must keep in mind the
id
to recognize the answer laterA network node initiating request sends a message to all known neighbors
For the first time when receiving this message, the network node decides whether to download the file (probability x%, mine is 50% right now)
If the file is not downloaded, the network node sends the message to all its neighbors, unless the neighbor IP matches the IP address of the transmitting node of the message
When the file is downloaded, a
file
type message is initiatedIn both cases, the message
id
and the forwarding network node IP must be memorized
Receiving a second message with the same
id
(or self-initiated) will be ignoredThe node initiating the request must take into consideration the possibility that the response is not guaranteed due to the unstable nature of the network
Return the contents of the file
The network node initiating the request sends a message to the neighbor from whom they
downloaded
the same message with the sameid
If the previous step fails, the message will be sent to all neighbors
For the first time when receiving this message, the network node decides if the file was its own (
id parameter
)If not, the network node sends the message to a neighbor who received the download request with the same
id
If the previous step failed (or no such neighbor is reported), the message will be sent to all neighbors, except if the neighbor IP matches the sender of the file in question with the IP address
If the file was requested by the node, the query body is parsed from the status and, if any, the contents of the file
Receiving a second message with the same id (or self-initiated) will be ignored
install
socket.io, express, axios, request, body-parser, event-emitter
To test I am using POSTMAN and here is request example:
localhost:4500/download?id=763145322224615&url=https://google.com&port=4500
I am sending download
request to node with port 4500
, id
is a random number which will be memorized by this node to recognize the answer later. url
is file to be downloaded.
Client (at least two clients to get it work!)
node client.js 4500
node client.js 4501
Server
node server.js
Server
"use strict";
const app = require("express")();
const http = require("http").Server(app);
const io = require("socket.io")(http);
var hosts = ;
app.get("/hosts", function(req, res)
res.send(hosts);
);
http.listen(3000, function()
console.log("listening on *:3000");
);
io.on("connection", function(socket)
const address = socket.handshake.address;
const ipAddress = address.substring(address.lastIndexOf(':') + 1, address.length);
const port = socket.handshake.query.port;
hosts.push(ip: ipAddress, port: port);
console.log(`A machine with $ipAddress:$port successfully connected!`);
socket.join("hosts");
console.log(`A machine successfully joined!`);
socket.emit("hosts", hosts);
// socket.broadcast.to("hosts").emit("hosts", hosts);
socket.on("disconnect", function() item.port !== port);
// socket.broadcast.to("hosts").emit("hosts", hosts);
);
);
Client
"use strict";
const io = require('socket.io-client');
const app = require('express')();
const http = require('http')
const server = http.Server(app);
const request = require('request');
const axios = require('axios');
const bodyParser = require('body-parser')
const EventEmitter = require('events');
class MyEmitter extends EventEmitter ;
const event = new MyEmitter();
app.use(bodyParser.urlencoded( extended: true));
app.use(bodyParser.json())
const states = "REQUEST": 1, "SEND": 2, "DOWNLOAD": 3, "FINISH": 4;
const errorCodes = "NOT_ACCEPTABLE": "NOT ACCEPTABLE", "OK": "OK";
const args = process.argv;
const myIpAddress = "127.0.0.1"
const myPort = args[2] || 4500;
const serverAddress = "127.0.0.1";
const serverPort = 3000;
const socket = io(`http://$serverAddress:$serverPort/`,
query: `port=$myPort`
);
const laziness = 0.5;
var hosts = ;
var requests = ;
server.listen(myPort, myIpAddress, () =>
console.log(`Listening $myIpAddress:$myPort`);
);
socket.on("hosts", data =>
//console.log("Received data: ", data)
hosts = data;
);
app.get("/download", (req, res) =>
const id = req.query.id;
const url = req.query.url;
const ip = req.connection.remoteAddress;
const port = req.query.port;
if (id == null );
app.get('/check', (req, res) =>
let id = req.query.id;
res.sendStatus(requests[id] != null && requests[id].state != states.REQUEST ? 200 : 204);
);
app.post('/file', (req, res) => requests[id].state === states.FINISH)
res.status(200).send(errorCodes.NOT_ACCEPTABLE);
return;
if (requests[id].host)
requests[id].state = states.FINISH;
console.log('StatusCode: ', req.body.status);
console.log('Mime-type: ', req.body['mime-type']);
console.log("Content: ", Buffer.from(req.body.content, "base64").toString("ascii"));
else
console.log('Sending back to host');
event.emit("sendBackToHost", id, req.body);
res.sendStatus(200);
);
event.on('check', (id) =>
axios.get(`http://$requests[id].ip:$requests[id].port/check?id=$id`)
.then(res =>
if (res.status === 204)
requests[id].url = encodeUrl(requests[id].url);
requests[id].host = true;
event.emit('sendNext', id);
else if (res.status === 200)
event.emit('downloadOrSend', id);
)
.catch(err =>
console.error('Error with checking', err);
)
);
event.on('downloadOrSend', (id) =>
if (isDownloadState())
axios.get(decodeUrl(requests[id].url))
.then(res =>
const body =
content: Buffer.from(res.data).toString('base64'),
status: res.status,
"mime-type": res.headers["content-type"]
;
requests[id].state = states.DOWNLOAD;
event.emit('sendBackToHost', id, body)
)
.catch(err =>
console.error('Error while downloading file', err.response);
)
return;
event.emit('sendNext', id);
)
event.on('sendBackToHost', (id, body) =>
axios.post(`http://$requests[id].ip:$requests[id].port/file?id=$id`, body)
.catch(err =>
console.error("Error while sending back to host", err.response);
event.emit('sendFileBackToAll', id, body);
);
);
event.on('sendNext', (id) =>
requests[id].state = states.SEND;
for (let h of hosts)
if (h.ip == requests[id].ip && h.port == requests[id].port) continue;
if (h.ip == myIpAddress && h.port == myPort) continue;
axios.get(`http://$h.ip:$h.port/download?id=$id&url=$requests[id].url&port=$myPort`)
.catch(err =>
console.error('Error while sending requests to neighbours', err.response);
);
);
event.on('sendFileBackToAll', (id, body) =>
for (let h of hosts)
if (h.ip == myIpAddress && h.port == myPort) continue;
axios.post(`http://$h.ip:$h.port/file?id=$id`, body)
.catch(err =>
console.error("Error while sending back to all hosts", err.response);
);
);
function isDownloadState()
return Math.random() >= laziness;
function encodeUrl(url)
return (decodeURIComponent(url) === url) ? encodeURIComponent(url) : url;
function decodeUrl(url)
return (decodeURIComponent(url) === url) ? url : decodeURIComponent(url);
setInterval(() =>
axios.get(`http://$serverAddress:$serverPort/hosts`)
.then(res =>
hosts = res.data;
)
.catch(err =>
console.error("Error while fetching data from server", err.response);
)
, 60000)
javascript node.js express.js socket.io axios
add a comment |Â
up vote
3
down vote
favorite
The goal of my project is to build a mini "anonymous" network (like Tor is) (command-line only
) using Node.js and frameworks (socket.io / axios / express). A network where I can download files (HTML etc) anonymously. I have central server
and nodes (clients
). At start each client connects to central server (using socket.io) and server appends it to the list hosts
. Each minute client asks server for latest list of alive nodes.
I came here because I did my best and I cannot see more bugs / errors / flaws. Also, I am not good at security and only on my way to learning deep.
I have some questions and I will be grateful if you advise how to improve my code:
- What can be improved and how?
- What about security?
- My node-chain isn't that good now. How I can make it longer (right now I have to set 1 minute timer and start nodes at different time but it is bad; in- fact that if some node will die in the middle, my code would be ruined, so I am looking for real-time long (at least 3 nodes) chain)
- Right now I am receiving the answer as HTML in my console. Is it possible to do so that if node localhost:4500 sends request I can see the answer as website at localhost:4500?
Maybe my central server
should create graf of clients
where each client
(node) will have 3 (strict) neighbor nodes, but how to implement that? (image visualisation below!)
My code is fully working and you can see it below with some rules that my project has.
URL (file) download request
If the node initiates this query itself, it must keep in mind the
id
to recognize the answer laterA network node initiating request sends a message to all known neighbors
For the first time when receiving this message, the network node decides whether to download the file (probability x%, mine is 50% right now)
If the file is not downloaded, the network node sends the message to all its neighbors, unless the neighbor IP matches the IP address of the transmitting node of the message
When the file is downloaded, a
file
type message is initiatedIn both cases, the message
id
and the forwarding network node IP must be memorized
Receiving a second message with the same
id
(or self-initiated) will be ignoredThe node initiating the request must take into consideration the possibility that the response is not guaranteed due to the unstable nature of the network
Return the contents of the file
The network node initiating the request sends a message to the neighbor from whom they
downloaded
the same message with the sameid
If the previous step fails, the message will be sent to all neighbors
For the first time when receiving this message, the network node decides if the file was its own (
id parameter
)If not, the network node sends the message to a neighbor who received the download request with the same
id
If the previous step failed (or no such neighbor is reported), the message will be sent to all neighbors, except if the neighbor IP matches the sender of the file in question with the IP address
If the file was requested by the node, the query body is parsed from the status and, if any, the contents of the file
Receiving a second message with the same id (or self-initiated) will be ignored
install
socket.io, express, axios, request, body-parser, event-emitter
To test I am using POSTMAN and here is request example:
localhost:4500/download?id=763145322224615&url=https://google.com&port=4500
I am sending download
request to node with port 4500
, id
is a random number which will be memorized by this node to recognize the answer later. url
is file to be downloaded.
Client (at least two clients to get it work!)
node client.js 4500
node client.js 4501
Server
node server.js
Server
"use strict";
const app = require("express")();
const http = require("http").Server(app);
const io = require("socket.io")(http);
var hosts = ;
app.get("/hosts", function(req, res)
res.send(hosts);
);
http.listen(3000, function()
console.log("listening on *:3000");
);
io.on("connection", function(socket)
const address = socket.handshake.address;
const ipAddress = address.substring(address.lastIndexOf(':') + 1, address.length);
const port = socket.handshake.query.port;
hosts.push(ip: ipAddress, port: port);
console.log(`A machine with $ipAddress:$port successfully connected!`);
socket.join("hosts");
console.log(`A machine successfully joined!`);
socket.emit("hosts", hosts);
// socket.broadcast.to("hosts").emit("hosts", hosts);
socket.on("disconnect", function() item.port !== port);
// socket.broadcast.to("hosts").emit("hosts", hosts);
);
);
Client
"use strict";
const io = require('socket.io-client');
const app = require('express')();
const http = require('http')
const server = http.Server(app);
const request = require('request');
const axios = require('axios');
const bodyParser = require('body-parser')
const EventEmitter = require('events');
class MyEmitter extends EventEmitter ;
const event = new MyEmitter();
app.use(bodyParser.urlencoded( extended: true));
app.use(bodyParser.json())
const states = "REQUEST": 1, "SEND": 2, "DOWNLOAD": 3, "FINISH": 4;
const errorCodes = "NOT_ACCEPTABLE": "NOT ACCEPTABLE", "OK": "OK";
const args = process.argv;
const myIpAddress = "127.0.0.1"
const myPort = args[2] || 4500;
const serverAddress = "127.0.0.1";
const serverPort = 3000;
const socket = io(`http://$serverAddress:$serverPort/`,
query: `port=$myPort`
);
const laziness = 0.5;
var hosts = ;
var requests = ;
server.listen(myPort, myIpAddress, () =>
console.log(`Listening $myIpAddress:$myPort`);
);
socket.on("hosts", data =>
//console.log("Received data: ", data)
hosts = data;
);
app.get("/download", (req, res) =>
const id = req.query.id;
const url = req.query.url;
const ip = req.connection.remoteAddress;
const port = req.query.port;
if (id == null );
app.get('/check', (req, res) =>
let id = req.query.id;
res.sendStatus(requests[id] != null && requests[id].state != states.REQUEST ? 200 : 204);
);
app.post('/file', (req, res) => requests[id].state === states.FINISH)
res.status(200).send(errorCodes.NOT_ACCEPTABLE);
return;
if (requests[id].host)
requests[id].state = states.FINISH;
console.log('StatusCode: ', req.body.status);
console.log('Mime-type: ', req.body['mime-type']);
console.log("Content: ", Buffer.from(req.body.content, "base64").toString("ascii"));
else
console.log('Sending back to host');
event.emit("sendBackToHost", id, req.body);
res.sendStatus(200);
);
event.on('check', (id) =>
axios.get(`http://$requests[id].ip:$requests[id].port/check?id=$id`)
.then(res =>
if (res.status === 204)
requests[id].url = encodeUrl(requests[id].url);
requests[id].host = true;
event.emit('sendNext', id);
else if (res.status === 200)
event.emit('downloadOrSend', id);
)
.catch(err =>
console.error('Error with checking', err);
)
);
event.on('downloadOrSend', (id) =>
if (isDownloadState())
axios.get(decodeUrl(requests[id].url))
.then(res =>
const body =
content: Buffer.from(res.data).toString('base64'),
status: res.status,
"mime-type": res.headers["content-type"]
;
requests[id].state = states.DOWNLOAD;
event.emit('sendBackToHost', id, body)
)
.catch(err =>
console.error('Error while downloading file', err.response);
)
return;
event.emit('sendNext', id);
)
event.on('sendBackToHost', (id, body) =>
axios.post(`http://$requests[id].ip:$requests[id].port/file?id=$id`, body)
.catch(err =>
console.error("Error while sending back to host", err.response);
event.emit('sendFileBackToAll', id, body);
);
);
event.on('sendNext', (id) =>
requests[id].state = states.SEND;
for (let h of hosts)
if (h.ip == requests[id].ip && h.port == requests[id].port) continue;
if (h.ip == myIpAddress && h.port == myPort) continue;
axios.get(`http://$h.ip:$h.port/download?id=$id&url=$requests[id].url&port=$myPort`)
.catch(err =>
console.error('Error while sending requests to neighbours', err.response);
);
);
event.on('sendFileBackToAll', (id, body) =>
for (let h of hosts)
if (h.ip == myIpAddress && h.port == myPort) continue;
axios.post(`http://$h.ip:$h.port/file?id=$id`, body)
.catch(err =>
console.error("Error while sending back to all hosts", err.response);
);
);
function isDownloadState()
return Math.random() >= laziness;
function encodeUrl(url)
return (decodeURIComponent(url) === url) ? encodeURIComponent(url) : url;
function decodeUrl(url)
return (decodeURIComponent(url) === url) ? url : decodeURIComponent(url);
setInterval(() =>
axios.get(`http://$serverAddress:$serverPort/hosts`)
.then(res =>
hosts = res.data;
)
.catch(err =>
console.error("Error while fetching data from server", err.response);
)
, 60000)
javascript node.js express.js socket.io axios
add a comment |Â
up vote
3
down vote
favorite
up vote
3
down vote
favorite
The goal of my project is to build a mini "anonymous" network (like Tor is) (command-line only
) using Node.js and frameworks (socket.io / axios / express). A network where I can download files (HTML etc) anonymously. I have central server
and nodes (clients
). At start each client connects to central server (using socket.io) and server appends it to the list hosts
. Each minute client asks server for latest list of alive nodes.
I came here because I did my best and I cannot see more bugs / errors / flaws. Also, I am not good at security and only on my way to learning deep.
I have some questions and I will be grateful if you advise how to improve my code:
- What can be improved and how?
- What about security?
- My node-chain isn't that good now. How I can make it longer (right now I have to set 1 minute timer and start nodes at different time but it is bad; in- fact that if some node will die in the middle, my code would be ruined, so I am looking for real-time long (at least 3 nodes) chain)
- Right now I am receiving the answer as HTML in my console. Is it possible to do so that if node localhost:4500 sends request I can see the answer as website at localhost:4500?
Maybe my central server
should create graf of clients
where each client
(node) will have 3 (strict) neighbor nodes, but how to implement that? (image visualisation below!)
My code is fully working and you can see it below with some rules that my project has.
URL (file) download request
If the node initiates this query itself, it must keep in mind the
id
to recognize the answer laterA network node initiating request sends a message to all known neighbors
For the first time when receiving this message, the network node decides whether to download the file (probability x%, mine is 50% right now)
If the file is not downloaded, the network node sends the message to all its neighbors, unless the neighbor IP matches the IP address of the transmitting node of the message
When the file is downloaded, a
file
type message is initiatedIn both cases, the message
id
and the forwarding network node IP must be memorized
Receiving a second message with the same
id
(or self-initiated) will be ignoredThe node initiating the request must take into consideration the possibility that the response is not guaranteed due to the unstable nature of the network
Return the contents of the file
The network node initiating the request sends a message to the neighbor from whom they
downloaded
the same message with the sameid
If the previous step fails, the message will be sent to all neighbors
For the first time when receiving this message, the network node decides if the file was its own (
id parameter
)If not, the network node sends the message to a neighbor who received the download request with the same
id
If the previous step failed (or no such neighbor is reported), the message will be sent to all neighbors, except if the neighbor IP matches the sender of the file in question with the IP address
If the file was requested by the node, the query body is parsed from the status and, if any, the contents of the file
Receiving a second message with the same id (or self-initiated) will be ignored
install
socket.io, express, axios, request, body-parser, event-emitter
To test I am using POSTMAN and here is request example:
localhost:4500/download?id=763145322224615&url=https://google.com&port=4500
I am sending download
request to node with port 4500
, id
is a random number which will be memorized by this node to recognize the answer later. url
is file to be downloaded.
Client (at least two clients to get it work!)
node client.js 4500
node client.js 4501
Server
node server.js
Server
"use strict";
const app = require("express")();
const http = require("http").Server(app);
const io = require("socket.io")(http);
var hosts = ;
app.get("/hosts", function(req, res)
res.send(hosts);
);
http.listen(3000, function()
console.log("listening on *:3000");
);
io.on("connection", function(socket)
const address = socket.handshake.address;
const ipAddress = address.substring(address.lastIndexOf(':') + 1, address.length);
const port = socket.handshake.query.port;
hosts.push(ip: ipAddress, port: port);
console.log(`A machine with $ipAddress:$port successfully connected!`);
socket.join("hosts");
console.log(`A machine successfully joined!`);
socket.emit("hosts", hosts);
// socket.broadcast.to("hosts").emit("hosts", hosts);
socket.on("disconnect", function() item.port !== port);
// socket.broadcast.to("hosts").emit("hosts", hosts);
);
);
Client
"use strict";
const io = require('socket.io-client');
const app = require('express')();
const http = require('http')
const server = http.Server(app);
const request = require('request');
const axios = require('axios');
const bodyParser = require('body-parser')
const EventEmitter = require('events');
class MyEmitter extends EventEmitter ;
const event = new MyEmitter();
app.use(bodyParser.urlencoded( extended: true));
app.use(bodyParser.json())
const states = "REQUEST": 1, "SEND": 2, "DOWNLOAD": 3, "FINISH": 4;
const errorCodes = "NOT_ACCEPTABLE": "NOT ACCEPTABLE", "OK": "OK";
const args = process.argv;
const myIpAddress = "127.0.0.1"
const myPort = args[2] || 4500;
const serverAddress = "127.0.0.1";
const serverPort = 3000;
const socket = io(`http://$serverAddress:$serverPort/`,
query: `port=$myPort`
);
const laziness = 0.5;
var hosts = ;
var requests = ;
server.listen(myPort, myIpAddress, () =>
console.log(`Listening $myIpAddress:$myPort`);
);
socket.on("hosts", data =>
//console.log("Received data: ", data)
hosts = data;
);
app.get("/download", (req, res) =>
const id = req.query.id;
const url = req.query.url;
const ip = req.connection.remoteAddress;
const port = req.query.port;
if (id == null );
app.get('/check', (req, res) =>
let id = req.query.id;
res.sendStatus(requests[id] != null && requests[id].state != states.REQUEST ? 200 : 204);
);
app.post('/file', (req, res) => requests[id].state === states.FINISH)
res.status(200).send(errorCodes.NOT_ACCEPTABLE);
return;
if (requests[id].host)
requests[id].state = states.FINISH;
console.log('StatusCode: ', req.body.status);
console.log('Mime-type: ', req.body['mime-type']);
console.log("Content: ", Buffer.from(req.body.content, "base64").toString("ascii"));
else
console.log('Sending back to host');
event.emit("sendBackToHost", id, req.body);
res.sendStatus(200);
);
event.on('check', (id) =>
axios.get(`http://$requests[id].ip:$requests[id].port/check?id=$id`)
.then(res =>
if (res.status === 204)
requests[id].url = encodeUrl(requests[id].url);
requests[id].host = true;
event.emit('sendNext', id);
else if (res.status === 200)
event.emit('downloadOrSend', id);
)
.catch(err =>
console.error('Error with checking', err);
)
);
event.on('downloadOrSend', (id) =>
if (isDownloadState())
axios.get(decodeUrl(requests[id].url))
.then(res =>
const body =
content: Buffer.from(res.data).toString('base64'),
status: res.status,
"mime-type": res.headers["content-type"]
;
requests[id].state = states.DOWNLOAD;
event.emit('sendBackToHost', id, body)
)
.catch(err =>
console.error('Error while downloading file', err.response);
)
return;
event.emit('sendNext', id);
)
event.on('sendBackToHost', (id, body) =>
axios.post(`http://$requests[id].ip:$requests[id].port/file?id=$id`, body)
.catch(err =>
console.error("Error while sending back to host", err.response);
event.emit('sendFileBackToAll', id, body);
);
);
event.on('sendNext', (id) =>
requests[id].state = states.SEND;
for (let h of hosts)
if (h.ip == requests[id].ip && h.port == requests[id].port) continue;
if (h.ip == myIpAddress && h.port == myPort) continue;
axios.get(`http://$h.ip:$h.port/download?id=$id&url=$requests[id].url&port=$myPort`)
.catch(err =>
console.error('Error while sending requests to neighbours', err.response);
);
);
event.on('sendFileBackToAll', (id, body) =>
for (let h of hosts)
if (h.ip == myIpAddress && h.port == myPort) continue;
axios.post(`http://$h.ip:$h.port/file?id=$id`, body)
.catch(err =>
console.error("Error while sending back to all hosts", err.response);
);
);
function isDownloadState()
return Math.random() >= laziness;
function encodeUrl(url)
return (decodeURIComponent(url) === url) ? encodeURIComponent(url) : url;
function decodeUrl(url)
return (decodeURIComponent(url) === url) ? url : decodeURIComponent(url);
setInterval(() =>
axios.get(`http://$serverAddress:$serverPort/hosts`)
.then(res =>
hosts = res.data;
)
.catch(err =>
console.error("Error while fetching data from server", err.response);
)
, 60000)
javascript node.js express.js socket.io axios
The goal of my project is to build a mini "anonymous" network (like Tor is) (command-line only
) using Node.js and frameworks (socket.io / axios / express). A network where I can download files (HTML etc) anonymously. I have central server
and nodes (clients
). At start each client connects to central server (using socket.io) and server appends it to the list hosts
. Each minute client asks server for latest list of alive nodes.
I came here because I did my best and I cannot see more bugs / errors / flaws. Also, I am not good at security and only on my way to learning deep.
I have some questions and I will be grateful if you advise how to improve my code:
- What can be improved and how?
- What about security?
- My node-chain isn't that good now. How I can make it longer (right now I have to set 1 minute timer and start nodes at different time but it is bad; in- fact that if some node will die in the middle, my code would be ruined, so I am looking for real-time long (at least 3 nodes) chain)
- Right now I am receiving the answer as HTML in my console. Is it possible to do so that if node localhost:4500 sends request I can see the answer as website at localhost:4500?
Maybe my central server
should create graf of clients
where each client
(node) will have 3 (strict) neighbor nodes, but how to implement that? (image visualisation below!)
My code is fully working and you can see it below with some rules that my project has.
URL (file) download request
If the node initiates this query itself, it must keep in mind the
id
to recognize the answer laterA network node initiating request sends a message to all known neighbors
For the first time when receiving this message, the network node decides whether to download the file (probability x%, mine is 50% right now)
If the file is not downloaded, the network node sends the message to all its neighbors, unless the neighbor IP matches the IP address of the transmitting node of the message
When the file is downloaded, a
file
type message is initiatedIn both cases, the message
id
and the forwarding network node IP must be memorized
Receiving a second message with the same
id
(or self-initiated) will be ignoredThe node initiating the request must take into consideration the possibility that the response is not guaranteed due to the unstable nature of the network
Return the contents of the file
The network node initiating the request sends a message to the neighbor from whom they
downloaded
the same message with the sameid
If the previous step fails, the message will be sent to all neighbors
For the first time when receiving this message, the network node decides if the file was its own (
id parameter
)If not, the network node sends the message to a neighbor who received the download request with the same
id
If the previous step failed (or no such neighbor is reported), the message will be sent to all neighbors, except if the neighbor IP matches the sender of the file in question with the IP address
If the file was requested by the node, the query body is parsed from the status and, if any, the contents of the file
Receiving a second message with the same id (or self-initiated) will be ignored
install
socket.io, express, axios, request, body-parser, event-emitter
To test I am using POSTMAN and here is request example:
localhost:4500/download?id=763145322224615&url=https://google.com&port=4500
I am sending download
request to node with port 4500
, id
is a random number which will be memorized by this node to recognize the answer later. url
is file to be downloaded.
Client (at least two clients to get it work!)
node client.js 4500
node client.js 4501
Server
node server.js
Server
"use strict";
const app = require("express")();
const http = require("http").Server(app);
const io = require("socket.io")(http);
var hosts = ;
app.get("/hosts", function(req, res)
res.send(hosts);
);
http.listen(3000, function()
console.log("listening on *:3000");
);
io.on("connection", function(socket)
const address = socket.handshake.address;
const ipAddress = address.substring(address.lastIndexOf(':') + 1, address.length);
const port = socket.handshake.query.port;
hosts.push(ip: ipAddress, port: port);
console.log(`A machine with $ipAddress:$port successfully connected!`);
socket.join("hosts");
console.log(`A machine successfully joined!`);
socket.emit("hosts", hosts);
// socket.broadcast.to("hosts").emit("hosts", hosts);
socket.on("disconnect", function() item.port !== port);
// socket.broadcast.to("hosts").emit("hosts", hosts);
);
);
Client
"use strict";
const io = require('socket.io-client');
const app = require('express')();
const http = require('http')
const server = http.Server(app);
const request = require('request');
const axios = require('axios');
const bodyParser = require('body-parser')
const EventEmitter = require('events');
class MyEmitter extends EventEmitter ;
const event = new MyEmitter();
app.use(bodyParser.urlencoded( extended: true));
app.use(bodyParser.json())
const states = "REQUEST": 1, "SEND": 2, "DOWNLOAD": 3, "FINISH": 4;
const errorCodes = "NOT_ACCEPTABLE": "NOT ACCEPTABLE", "OK": "OK";
const args = process.argv;
const myIpAddress = "127.0.0.1"
const myPort = args[2] || 4500;
const serverAddress = "127.0.0.1";
const serverPort = 3000;
const socket = io(`http://$serverAddress:$serverPort/`,
query: `port=$myPort`
);
const laziness = 0.5;
var hosts = ;
var requests = ;
server.listen(myPort, myIpAddress, () =>
console.log(`Listening $myIpAddress:$myPort`);
);
socket.on("hosts", data =>
//console.log("Received data: ", data)
hosts = data;
);
app.get("/download", (req, res) =>
const id = req.query.id;
const url = req.query.url;
const ip = req.connection.remoteAddress;
const port = req.query.port;
if (id == null );
app.get('/check', (req, res) =>
let id = req.query.id;
res.sendStatus(requests[id] != null && requests[id].state != states.REQUEST ? 200 : 204);
);
app.post('/file', (req, res) => requests[id].state === states.FINISH)
res.status(200).send(errorCodes.NOT_ACCEPTABLE);
return;
if (requests[id].host)
requests[id].state = states.FINISH;
console.log('StatusCode: ', req.body.status);
console.log('Mime-type: ', req.body['mime-type']);
console.log("Content: ", Buffer.from(req.body.content, "base64").toString("ascii"));
else
console.log('Sending back to host');
event.emit("sendBackToHost", id, req.body);
res.sendStatus(200);
);
event.on('check', (id) =>
axios.get(`http://$requests[id].ip:$requests[id].port/check?id=$id`)
.then(res =>
if (res.status === 204)
requests[id].url = encodeUrl(requests[id].url);
requests[id].host = true;
event.emit('sendNext', id);
else if (res.status === 200)
event.emit('downloadOrSend', id);
)
.catch(err =>
console.error('Error with checking', err);
)
);
event.on('downloadOrSend', (id) =>
if (isDownloadState())
axios.get(decodeUrl(requests[id].url))
.then(res =>
const body =
content: Buffer.from(res.data).toString('base64'),
status: res.status,
"mime-type": res.headers["content-type"]
;
requests[id].state = states.DOWNLOAD;
event.emit('sendBackToHost', id, body)
)
.catch(err =>
console.error('Error while downloading file', err.response);
)
return;
event.emit('sendNext', id);
)
event.on('sendBackToHost', (id, body) =>
axios.post(`http://$requests[id].ip:$requests[id].port/file?id=$id`, body)
.catch(err =>
console.error("Error while sending back to host", err.response);
event.emit('sendFileBackToAll', id, body);
);
);
event.on('sendNext', (id) =>
requests[id].state = states.SEND;
for (let h of hosts)
if (h.ip == requests[id].ip && h.port == requests[id].port) continue;
if (h.ip == myIpAddress && h.port == myPort) continue;
axios.get(`http://$h.ip:$h.port/download?id=$id&url=$requests[id].url&port=$myPort`)
.catch(err =>
console.error('Error while sending requests to neighbours', err.response);
);
);
event.on('sendFileBackToAll', (id, body) =>
for (let h of hosts)
if (h.ip == myIpAddress && h.port == myPort) continue;
axios.post(`http://$h.ip:$h.port/file?id=$id`, body)
.catch(err =>
console.error("Error while sending back to all hosts", err.response);
);
);
function isDownloadState()
return Math.random() >= laziness;
function encodeUrl(url)
return (decodeURIComponent(url) === url) ? encodeURIComponent(url) : url;
function decodeUrl(url)
return (decodeURIComponent(url) === url) ? url : decodeURIComponent(url);
setInterval(() =>
axios.get(`http://$serverAddress:$serverPort/hosts`)
.then(res =>
hosts = res.data;
)
.catch(err =>
console.error("Error while fetching data from server", err.response);
)
, 60000)
javascript node.js express.js socket.io axios
asked Apr 3 at 13:13
spyrox
163
163
add a comment |Â
add a comment |Â
1 Answer
1
active
oldest
votes
up vote
1
down vote
I don't know javascript but some things got me wondering. I apologize in advance if I overlooked the obvious. Most of the things I point out here you can read about on the OWASP site. It's a great resource.
- I couldn't tell if you are validating input, this is definitely a good idea. For example the urls that are being passed.
- You should not be accepting raw HTML, this would be good to sanitize first.
- The central server maintains a list of known hosts, but how do the clients connecting to the central server know they are not talking to a 'malicious' one? You can counter this by using public/private-keys(take a look at libsodium), so you could for example have the central server sign the hosts filelist. Then have the central hosts public key hard-coded into the clients, so that they can verify the file is 'trusted'.
- All data is transmitted in the cleartext as I can tell, so an obvious improvement would be expanding on the public-key approach and have all nodes generate a keypair, where the public keys belonging to each node, are listed in the hosts file/list. Then whenever a node sends data to another node, that data can also be encrypted (This is much like an approach of TOR if I remember correctly).
add a comment |Â
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
1
down vote
I don't know javascript but some things got me wondering. I apologize in advance if I overlooked the obvious. Most of the things I point out here you can read about on the OWASP site. It's a great resource.
- I couldn't tell if you are validating input, this is definitely a good idea. For example the urls that are being passed.
- You should not be accepting raw HTML, this would be good to sanitize first.
- The central server maintains a list of known hosts, but how do the clients connecting to the central server know they are not talking to a 'malicious' one? You can counter this by using public/private-keys(take a look at libsodium), so you could for example have the central server sign the hosts filelist. Then have the central hosts public key hard-coded into the clients, so that they can verify the file is 'trusted'.
- All data is transmitted in the cleartext as I can tell, so an obvious improvement would be expanding on the public-key approach and have all nodes generate a keypair, where the public keys belonging to each node, are listed in the hosts file/list. Then whenever a node sends data to another node, that data can also be encrypted (This is much like an approach of TOR if I remember correctly).
add a comment |Â
up vote
1
down vote
I don't know javascript but some things got me wondering. I apologize in advance if I overlooked the obvious. Most of the things I point out here you can read about on the OWASP site. It's a great resource.
- I couldn't tell if you are validating input, this is definitely a good idea. For example the urls that are being passed.
- You should not be accepting raw HTML, this would be good to sanitize first.
- The central server maintains a list of known hosts, but how do the clients connecting to the central server know they are not talking to a 'malicious' one? You can counter this by using public/private-keys(take a look at libsodium), so you could for example have the central server sign the hosts filelist. Then have the central hosts public key hard-coded into the clients, so that they can verify the file is 'trusted'.
- All data is transmitted in the cleartext as I can tell, so an obvious improvement would be expanding on the public-key approach and have all nodes generate a keypair, where the public keys belonging to each node, are listed in the hosts file/list. Then whenever a node sends data to another node, that data can also be encrypted (This is much like an approach of TOR if I remember correctly).
add a comment |Â
up vote
1
down vote
up vote
1
down vote
I don't know javascript but some things got me wondering. I apologize in advance if I overlooked the obvious. Most of the things I point out here you can read about on the OWASP site. It's a great resource.
- I couldn't tell if you are validating input, this is definitely a good idea. For example the urls that are being passed.
- You should not be accepting raw HTML, this would be good to sanitize first.
- The central server maintains a list of known hosts, but how do the clients connecting to the central server know they are not talking to a 'malicious' one? You can counter this by using public/private-keys(take a look at libsodium), so you could for example have the central server sign the hosts filelist. Then have the central hosts public key hard-coded into the clients, so that they can verify the file is 'trusted'.
- All data is transmitted in the cleartext as I can tell, so an obvious improvement would be expanding on the public-key approach and have all nodes generate a keypair, where the public keys belonging to each node, are listed in the hosts file/list. Then whenever a node sends data to another node, that data can also be encrypted (This is much like an approach of TOR if I remember correctly).
I don't know javascript but some things got me wondering. I apologize in advance if I overlooked the obvious. Most of the things I point out here you can read about on the OWASP site. It's a great resource.
- I couldn't tell if you are validating input, this is definitely a good idea. For example the urls that are being passed.
- You should not be accepting raw HTML, this would be good to sanitize first.
- The central server maintains a list of known hosts, but how do the clients connecting to the central server know they are not talking to a 'malicious' one? You can counter this by using public/private-keys(take a look at libsodium), so you could for example have the central server sign the hosts filelist. Then have the central hosts public key hard-coded into the clients, so that they can verify the file is 'trusted'.
- All data is transmitted in the cleartext as I can tell, so an obvious improvement would be expanding on the public-key approach and have all nodes generate a keypair, where the public keys belonging to each node, are listed in the hosts file/list. Then whenever a node sends data to another node, that data can also be encrypted (This is much like an approach of TOR if I remember correctly).
edited Apr 4 at 7:50
answered Apr 4 at 7:37
user159822
add a comment |Â
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f191161%2fmini-tor-implementation-cli-only-anonymous-network%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password