I am trying to make a proxy server in Node.js which can block URLs based off of a Regex expression and also has basic authentication, to be used as a proxy with IOS devices.
Here is my current code:
let http = require('http');
let net = require('net');
let httpProxy = require('http-proxy');
let url = require('url');
let fs = require('fs');
let auth = require('basic-auth');
const port = process.env.PORT || 8080;
let proxy = httpProxy.createServer();
let blacklist = [/.*example\.com$/];
function inBlacklist(url) {
return blacklist.some(function (blacklistItem) {
return blacklistItem.test(url);
});
}
let logStream = fs.createWriteStream('log.txt', { flags: 'a' });
console.log("Booting Up | Port", port);
let allowedCredentials = [
'root:root'
]
function check (username, password) {
if (username && password) {
if(allowedCredentials.indexOf(`${username}:${password}`) > -1){
return true;
} else return false;
} else {
return false;
}
};
var server = http.createServer(function (req, res) {
var credentials = auth(req);
if (!credentials || !check(credentials.name, credentials.pass)) {
res.statusCode = 401
res.setHeader('WWW-Authenticate', 'Basic realm="Please log in using your given username and password."')
return res.end('Access denied');
} else {
res.end('Access granted')
}
var serverUrl;
try { serverUrl = url.parse(req.url); }
catch { console.log(0); return; }
var shouldBlock = false;
try { shouldBlock = inBlacklist(serverUrl.hostname); } catch {
console.log(1); return;
}
logStream.write(`CONNECT1: ${req.url}\nHOSTNAME: ${serverUrl.hostname}\nshouldBlock: ${shouldBlock}\nreqURL: ${req.url}\n---------\n`);
if (shouldBlock) {
try {
return proxy.web(req, res, { target: '0.0.0.0' }, function () {
res.writeHead(404);
res.end('Not found.');
});
} catch { console.log(3); return; }
}
try { proxy.web(req, res, { target: req.url, secure: false }, function (e) { console.log("Proxy.web Accept Error"); res.writeHead(404); res.end('Not found. (P.W. Accept Error)'); }); } catch { console.log(2); }
}).listen(port, '0.0.0.0', () => {
console.log("Listening at: http://example.com:" + port);
});
server.on('listening', () => {
console.log(`Server is listening on port ${server.address().port}`);
});
server.on('close', function () {
logStream.write('server closed\n');
logStream.end();
});
server.on('error', function (err) {
logStream.write(`ERROR: ${err}\n---------\n`);
console.log('Server error:', err);
});
server.on('connect', function (req, socket) {
var reqport = req.url.split(':')[1];
var serverUrl;
if (reqport == 443) {
try { serverUrl = url.parse("https://" + req.url); }
catch (err) { console.log(err); return; }
} else if (reqport == 80) {
try { serverUrl = url.parse("http://" + req.url); }
catch (err) { console.log(err); return; }
} else return;
var shouldBlock = false;
try { shouldBlock = inBlacklist(serverUrl.hostname); } catch {
console.log(1); return;
}
logStream.write(`CONNECT2: ${req.url}\nHOSTNAME: ${serverUrl.hostname}\nshouldBlock: ${shouldBlock}\nreqURL: ${req.url}\n---------\n`);
if (shouldBlock) {
try {
socket.write('HTTP/1.1 404 Not Found\r\n' +
'\r\nNot found.');
}
catch { console.log("Caught error"); }
return socket.end();
}
var srvSocket = net.connect(serverUrl.port, serverUrl.hostname, function () {
try {
socket.write('HTTP/1.1 200 Connection Established\r\n' +
'Proxy-agent: Node-Proxy\r\n' +
'\r\n');
} catch {
logStream.write(`ERROR WRITING\n---------\n`);
}
srvSocket.pipe(socket).on('error', (err) => {});
socket.pipe(srvSocket).on('error', (err) => {});
}).on('error', (err) => err);
});
Is there any better way to do this? I am getting frequent errors with the srvSocket socket disconnecting.
Most importantly, the authentication doesn't work. For some devices, no authentication is required in the IOS settings, while on others authentication is required but doesn't matter what username and password are inputted.
Why does this happen?
Related
It is required to receive requests from the required IP addresses at the link 127.0.0.1:3000/test in the get format on nodejs and get the json file. When sending a GET request, a 404 error is generated according to the code below
http.createServer((request, response) => {
console.log(request.url);
console.log(request.method);
console.log(request.headers);
console.log(request.socket.remoteAddress);
if (request.method === "GET") {
console.log(`Requested address: ${request.url}`);
const filePath = request.url.substr(1);
fs.access(filePath, fs.constants.R_OK, err => {
if (err) {
response.statusCode = 404;
response.end("Resourse not found!");
} else {
fs.createReadStream(filePath).pipe(response);
}
});
} else {
console.log(`Requested address: ${request.url}`);
}
}).listen(3000, function() {
console.log("Server started at 3000");
});
I would suggest using express.
const app = require('express')();
const fs = require('fs');
app.get('/test', (request, response), async () => {
fs.createReadStream('./test.json').pipe(response);
});
app.listen(3000);
Or if you're looking for a more dynamic approach.
app.get('/:filePath', (request, response), async () => {
const { filePath } = req.params;
fs.access(filePath, fs.constants.R_OK, err => {
if (err) {
res.status(404).send('Resourse not found!');
} else {
fs.createReadStream(filePath).pipe(response);
}
});
});
I included the socket.io.js in client and also included the custom created socket.js for getting the responses from websocket server to client,when i loading this page in browser automatically stopped the websocket server and in browser console tells WebSocket connection to 'ws://localhost:8000/socket.io/?EIO=3&transport=websocket&sid=2p1ZYDAflHMHiL70AAAA' failed: Connection closed before receiving a handshake response
user defined socket.js code is given below
var socket = io();
var actionItems = []
var beginTakingAction = false
var strOut;
socket.on('transcript', function(x) {
var div = $('div.transcription')
div.html(x);
console.log("transcript " + x);
if (!scrolling) {
div.scrollTop(div[0].scrollHeight);
}
})
socket.on('action', function(x) {
console.log('sending action',x);
actionItems.push(x)
$('div.action').html(actionItems[actionItems.length-1]);
})
socket.on('sentiment', function(x) {
sentimentChart.update(x)
})
socket.on('nlp', function(x) {
wordLengthDistChart.update(x.wordLenghDist);
posTagDistChart.update(x.posTagDist);
})
socket.on('keywords', function(x) {
keywordChart.update(x)
})
socket.on('status', function(status) {
$('div.status').html("status: " + status);
if (status == "connected") {
sentimentChart.reset()
keywordChart.reset()
wordLengthDistChart.reset()
posTagDistChart.reset()
$('div.transcription').html('');
}
})
please give any suggesstions??
my server code is given below
require('dotenv').config()
var WebSocketServer = require('websocket').server;
var http = require('http');
var HttpDispatcher = require('httpdispatcher');
var dispatcher = new HttpDispatcher();
const fs = require('fs');
const winston = require('winston')
winston.level = process.env.LOG_LEVEL || 'info'
var AsrClient = require('./lib/asrClient')
var asrActive = false
var myAsrClient;
var engineStartedMs;
var connections = []
//Create a server
var server = http.createServer(function(req, res) {
handleRequest(req,res);
});
// Loading socket.io
var io = require('socket.io').listen(server);
// When a client connects, we note it in the console
io.sockets.on('connection', function (socket) {
winston.log('info','A client is connected!');
});
var wsServer = new WebSocketServer({
httpServer: server,
autoAcceptConnections: true,
binaryType: 'arraybuffer'
});
//Lets use our dispatcher
function handleRequest(request, response){
try {
//log the request on console
winston.log('info', 'handleRequest',request.url);
//Dispatch
dispatcher.dispatch(request, response);
} catch(err) {
console.log(err);
}
}
dispatcher.setStatic('/public');
dispatcher.setStaticDirname('public');
dispatcher.onGet("/", function(req, res) {
winston.log('info', 'loading index');
winston.log('info', 'port', process.env.PORT)
fs.readFile('./public/index.html', 'utf-8', function(error, content) {
winston.log('debug', 'loading Index');
res.writeHead(200, {"Content-Type": "text/html"});
res.end(content);
});
});
// Serve the ncco
dispatcher.onGet("/ncco", function(req, res) {
fs.readFile('./ncco.json', function(error, data) {
winston.log('debug', 'loading ncco');
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(data, 'utf-8');
});
});
dispatcher.onPost("/terminate", function(req, res) {
winston.log('info', 'terminate called');
wsServer.closeAllConnections();
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end();
});
wsServer.on('connect', function(connection) {
connections.push(connection);
winston.log('info', (new Date()) + ' Connection accepted' + ' - Protocol Version ' + connection.webSocketVersion);
connection.on('message', function(message) {
if (message.type === 'utf8') {
try {
var json = JSON.parse(message.utf8Data);
winston.log('info', "json", json['app']);
if (json['app'] == "audiosocket") {
VBConnect();
winston.log('info', 'connecting to VB');
}
} catch (e) {
winston.log('error', 'message error catch', e)
}
winston.log('info', "utf ",message.utf8Data);
}
else if (message.type === 'binary') {
// Reflect the message back
// connection.sendBytes(message.binaryData);
if (myAsrClient != null && asrActive) {
winston.log('debug', "sendingDate ",message.binaryData);
myAsrClient.sendData(message.binaryData)
}
}
});
connection.on('close', function(reasonCode, description) {
winston.log('info', (new Date()) + ' Peer ' + connection.remoteAddress + ' disconnected.');
wsServer.closeAllConnections();
});
});
wsServer.on('close', function(connection) {
winston.log('info', 'socket closed');
if (asrActive) {
io.sockets.emit('status', "disconnected");
winston.log('info', 'trying to close ASR client');
myAsrClient.close();
myAsrClient = null;
asrActive = false;
}
else {
winston.log('info', 'asr not active, cant close');
}
})
wsServer.on('error', function(error) {
winston.log('error', 'Websocket error', error);
})
var port = process.env.PORT || 8000
server.listen(port, function(){
winston.log('info', "Server listening on :%s", port);
});
My nodejs app is working well neither sockets server. Its connecting with user side but I can't handle any events.
var app = require("express")();
var http = require("http").createServer(app);
var io = require("socket.io")(http);
http.listen(appSettings.RUNNING_PORT, function () {
globals.debug('Server is running on port: ' + appSettings.RUNNING_PORT, 'success');
});
io.set('authorization', function (handshakeData, accept) {
if (handshakeData && handshakeData.headers && handshakeData.headers.referer) {
var domain = handshakeData.headers.referer.replace('http://', '').replace('https://', '').split(/[/?#]/)[0];
if ('**' == domain) {
accept(null, true);
} else {
globals.debug('Bad site authentication data, game will be disabled.', 'danger');
return accept('Bad site authentication data, game will be disabled.', false);
}
} else {
accept('Failed transaction', false);
}
io.use(function (sock, next) {
var handshakeData = sock.request;
var userToken = handshakeData._query.key;
users.prepare(io, []);
users.defineUser(userToken, sock.id, next);
// start the game
game.prepare(io, []);
game.startPolling();
});
});
so I'm connecting here and calling for some methods. users.defineUser(userToken, sock.id, next);
this.defineUser = function (token, sockID, next) {
if (token) {
Promise.try(function () {
return db('users')
.where('key', '=', token)
.orderBy('id', 'desc')
.limit(1);
}).then(function (result) {
if (result && result.length > 0) {
self.io.to(sockID).emit('connect-success', {
message: 'Successfully connected',
data: {
name: result[0].name
}
});
globals.debug('User '+ result[0].name +' connected as ' + sockID, 'success');
next('Successfully connected', true);
} else {
self.io.to(sockID).emit('global-error', {
message: 'Only connected users are available to play'
});
next(false, false);
}
}).catch(function (e) {
if (e.code) {
self.io.to(sockID).emit('global-error', {
message: 'There was a problem with our database, please try later. ' + e.code
});
next(false, false);
}
});
} else {
self.io.to(sockID).emit('global-error', {
message: 'Only connected users are available to play'
});
next(false, false);
}
};
so I can see debug for "User Sandra connected as /#Q82F5WCvLZvgy65YAAAB" but when I try to send anything to user it does not work.
Even in frontend I can see that app were connected with user by calling socket.on('connection) method. So where the problem could be?
i am completely newbie in node.js, and trying learn how it actually works. I know that by default all node.js function calls are asynchronous. Now i need LDAP authentication in my application where i need wait for the server response to check whether the user credentials are right or wrong.The ldap part is working fine but i am not sure on how to return data from a function call in synchronous way. below is the part of my code.
router.js
var express = require('express');
var router = express.Router();
var tools = require('./authenticateUser');
router.post('/authenticateUser', function(req, res) {
// In the below line i am calling the method which
// should return the userDN (a string)
tools.searchUser(req.body.user, req.body.passwd);
res.render('home.jade');
});
authenticateUser.js
module.exports = {
searchUser : function (username, password) {
adminDN = *************;
adminPassword = '*********';
baseDN = '***';
var ldap = require('ldapjs');
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
var adminClient = ldap.createClient({
url: '*******'
});
var opts = {
filter: '(&(objectClass=userProxyFull)(sAMAccountName=' + username + '))',
scope: 'sub',
attribute: ['sAMAccountName']
};
console.log('--- going to try to connect user ---');
try {
adminClient.bind(adminDN, adminPassword, function (error) {
if (error) {
console.log(error.message);
adminClient.unbind(function (error) {
if (error) {
console.log(error.message);
} else {
console.log('adminClient disconnected');
}
});
} else {
// Searching Client ID in LDS
adminClient.search(baseDN, opts, function (error, search) {
console.log('Searching.....' + userDN);
search.on('searchEntry', function (entry) {
if (entry.object) {
// Here i need to return the object back
//to the router.js from where i call in a synchronous way
adminClient.unbind(function (error) {
if (error) {
console.log(error.message);
}
});
}
});
search.on('error', function (error) {
console.error('error: ' + error.message);
});
});
}
});
} catch (error) {
console.log(error);
adminClient.unbind(function (error) {
if (error) {
console.log(error.message);
} else {
console.log('client disconnected');
}
});
} finally {
adminClient.unbind(function (error) {
if (error) {
console.log(error.message);
} else {
console.log('client disconnected');
}
});
}
},
};
You have to pass res.render('home.jade') as a function(the callback) to your searchUser function.
It should look like
tools.searchUser(req.body.user,
req.body.password,
res}
)
searchUser function
searchUser : function (username, password,res) {
...
finally(){
res.render('home.jade');
}
}
I've set up a NodeJS server which can be accessed by a client. Every once in a while it's necessary to let the server connect to a second server and feed the information retrieved back to the client.
Connecting to the second server is the easy part, but to be honest I have no idea how to send it back to the client. res.write seems to be forbidden during the connection with the second server.
The connection from the client is handled by handleGetRequest. The connection with the second server starts at http.get.
var http = require('http');
var url = require('url');
var server = http.createServer(function(req, res) {
var url_parsed = url.parse(req.url, true);
if (req.method ==='GET') {
handleGetRequest(res, url_parsed);
} else {
res.end('Method not supported');
}
});
handleGetRequest = function(res, url_parsed) {
if (url_parsed.path == '/secondary') {
var OPTIONS = {
hostname: "localhost",
port: "8900",
path: "/from_primary"
}
http.get(OPTIONS, function(secget) {
resget.on('data', function(chunk) {
// either store 'chunk' for later use or send directly
});
}).on('error', function(e) {
console.log("Error " + e.message);
});
} else {
res.writeHead(404);
}
res.end('Closed');
};
server.listen(8000);
How do I send the chunk from http.request to the client?
I thinks passing the callback to the handleGetRequest will fix this issue:
if (req.method === 'GET') {
handleGetRequest(url_parsed, function (err, response) {
if (err) {
return res.sendStatus(500);
}
res.json(response);
});
} else {
res.end('Method not supported');
}
handleGetRequest = function (url_parsed, callback) {
// OPTIONS ...
http.get(OPTIONS, function(resget) {
var data = '';
resget.on('data', function(chunk) {
data += chunk;
});
resget.on('end', function() {
callback(null, data);
});
}).on('error', function(e) {
callback(e);
});
}
Thanks to #TalgatMedetbekov for the suggestions. I managed to implement it like this:
var http = require('http');
var url = require('url');
var server = http.createServer(function(req, res) {
var url_parsed = url.parse(req.url, true);
if (req.method ==='GET') {
handleGetRequest(res, url_parsed);
} else {
res.end('Method not supported');
}
});
handleGetSecondaryRequest = function(callback, res) {
var OPTIONS = {
hostname: "localhost",
port: "8900",
path: "/from_primary"
}
var data = null;
http.get(OPTIONS, function(func, data) {
func.on('data', function(chunk) {
data += chunk;
});
func.on('end', function() {
callback(res, data);
});
}).on('error', function(e) {
callback(res, e);
})
};
var secReqCallback = function(res, recData)
{
res.write(recData);
res.end("END");
};
handleGetRequest = function(res, url_parsed) {
if (url_parsed.path == '/secondary') {
handleGetSecondaryRequest(secReqCallback, res);
} else {
res.writeHead(404);
}
};
server.listen(8000);
It works, kind of. There's an 'undefined' in front of the string which I can't find the cause for, but the basic functionality works perfect.
The callback construction is necessary to synchronize the asynchronous nature of NodeJS.