'use strict' const express = require('express') const net = require('net') const bodyParser = require('body-parser') const fs = require('fs') const torm = require('./tor.js') const logm = require('./log.js') const timeout_sock = 120 * 60 * 1000 // 120 minute * 60 second/minute * 1000 ms/second const counter = function*(count) { while (true) { yield count count++ } } const idgen = counter(0) const socks = {} const clean_sock = (tor, sock_id) => () => { if (!socks[sock_id]) { console.error(`Server ${sock_id} does not exist`) return "Unable to find the desired server" } if (socks[sock_id].timer) clearTimeout(socks[sock_id].timer) if (socks[sock_id].hs) tor.destroyHiddenService(socks[sock_id].hs, err => err ? console.error(err) : null) delete socks[sock_id] console.info(`Server ${sock_id} has been cleaned`) return null } const register_routes = (app, echo_server, tor) => { app.post('/hidden_service', (req, res) => { const id = idgen.next().value const port = echo_server.address().port const to = setTimeout(clean_sock(tor, id), timeout_sock) tor.createHiddenService( [{virtualPort: port, target: `127.0.0.1:${port}`}], (err, data) => { if (err) { console.error("Unable to create Tor Hidden Service", err) res.send({err: err}) return } socks[id] = {timer: to, hs: data.serviceId} console.info(`Service online at ${data.serviceId}.onion:${port} for ${timeout_sock}ms`) res.send({err: null, id: id, hs: data.serviceId, port: port}) }) }) app.delete('/hidden_service', (req, res) => { const sock_id = req.body.id const err = clean_sock(tor, sock_id)() res.send({err: err}) console.info(`Server ${sock_id} has been deleted with error "${err}"`) }) } const init_http = (echo_server, tor) => new Promise((resolve, reject) => { const app = express() app.use(bodyParser.json()) register_routes(app, echo_server, tor) app.listen(3000, () => { console.info("HTTP module has been inited") resolve(app) }) }) const init_echo = new Promise((resolve, reject) => { const echo_server = net.createServer() echo_server .on('error', err => { console.error("Unable to create socket", err) reject(err) }) .on('connection', socket => socket.on('data', socket.write)) // echo socket .on('listening', () => { console.info("Echo module has been inited") resolve(echo_server) }) .listen() }) const init = () => { Promise.all([init_echo, logm.init.then(res => torm.init(res[0], res[1]))]) .then(values => init_http(values[0], values[1])) .catch(console.error) } init()