I am doing a Chrome Application using the new Socket API (Chrome.sockets.tcp). I have been able to successfully get all HTTP requests working without any issue. The problem that I have run into is the HTTPS login with TLS handshake. We created a Visual Studio C# (RestRequest) application. We are able to connect using HTTPS. Using Wireshark, I notice that the successful communication was achieved using the TLSv1.
I have tried a variety of solutions and referenced/experimented with the below links and tried to come up with a solution.
https://groups.google.com/a/chromium.org/forum/#!msg/net-dev/U2ecAARKvAg/WI1WrSlaOPMJ
SSL Client Authentication with Certificate in Chrome App
Plus many more links! I have written a pile of test applications, but all reach a dead end after the initial handshake.
The following code sequence seems to get the handshake done, but I cannot send the login post. It seems as though the socket is messed up after the handshake. (WireShark shows all com’s were successful up until the login post).
var that = this;
chrome.sockets.tcp.create({
persistent: false,
name: "hc",
bufferSize: 8192
}, function (createInfo) {
console.log("create info = " + JSON.stringify(createInfo));
if (chrome.runtime.lastError) {
error('Unable to create socket: ' + chrome.runtime.lastError.message);
}
that._socketId = createInfo.socketId;
chrome.sockets.tcp.setPaused(that._socketId, true, function () {
chrome.sockets.tcp.connect(that._socketId, that._httpHost, that._httpPort, function (result) {
chrome.sockets.tcp.onReceive.addListener(that._onReceive.bind(this));
chrome.sockets.tcp.onReceiveError.addListener(that._onReceiveError.bind(this));
chrome.sockets.tcp.secure(that._socketId, function (secureResult) {
chrome.sockets.tcp.send(that._socketId, str2ab('POST / HTTP/1.1\r\nHOST: ' + that._httpHost + '\r\n\r\n'), function (sendResult) {});
});
});
});
});
I have tried implementing the TLSSocket from nmp forge and I get the same result as the example above.
We have to use TCP for this application, mainly for cookie support in a Chrome App.
Does anybody have a solution or suggestion? We have put in a lot of hours with trial and error, and seems like we have hit a dead end.
You need to unpause the socket after it's secured. e.g. chrome.sockets.tcp.setPaused(that._socketId, false, ...)
Related
I'm trying to connect to a WAMP websocket server using Python and subscribe to receive messages, but I'm not able to achieve it. I have managed to connect using Autobahn on JS with this code:
< script src = "autobahn.js" > < /script> <script >
var conn = new ab.Session('ws://examplehost.com:8443/ws',
function() {
conn.subscribe('channel', function(topic, data) {
console.log(data);
alert('New data arrived: "' + topic + '" : ' + data.title);});},
function() {
console.warn('WebSocket connection closed');
}, {'skipSubprotocolCheck': true});
</script>
But using the same library on Python with below code results on 404 error:
from autobahn.asyncio.wamp import ApplicationSession, ApplicationRunner
class Component(ApplicationSession):
async def onJoin(self, details):
def on_event(i):
print("New data arrived: {}".format(i))
await self.subscribe(on_event, 'channel')
if __name__ == '__main__':
url = "ws://examplehost.com:8443/ws"
runner = ApplicationRunner(url)
runner.run(Component)
And this is the error I get:
failing WebSocket opening handshake ('WebSocket connection upgrade failed (404 - NotFound)')
dropping connection to peer tcp4:123.123.123.123:8443 with abort=True: WebSocket connection upgrade failed (404 - NotFound)
Any idea on how to solve this? After searching a lot maybe using the path /ws on the server is causing some issues, but I'm not sure. I have also tried with many other Python modules, but not luck.
This looks like a webserver issue. My understanding is websockets are created by upgrading reglar HTTP connections.
You need to configure the web server, and any proxy in the middle, to upgrade the configuration.
I've mostly encountered this with nginx. This looks like a good example.
I am running an SMTP Server using http://nodemailer.com/extras/smtp-server/ to accept all the mail submissions.
When the mail submission agent uses STARTTLS I get the following error.
5|producer | [2020-10-09 07:28:52] DEBUG [#ff7cqlwi7rat6z2k] C: EHLO qa.mydomain.com
5|producer | [2020-10-09 07:28:52] DEBUG [#ff7cqlwi7rat6z2k] S: 421 mydomain.com You talk too soon
5|producer | [2020-10-09 07:28:52] INFO [#ff7cqlwi7rat6z2k] Connection closed to 91.198.201.301
However, this happens only with some clients and I have tried with few other tools and it upgrades the connection to TLS without any issue.
Below are my server configuration options.
SMTPServerOptions = {
secure: false,
hideSTARTTLS:true,
authOptional: true,
debug: true,
logger: true,
onAuth,
onData
}
if(conf.tls) {
SMTPServerOptions.ca = fs.readFileSync('./certificates/chain.pem', 'ascii')
SMTPServerOptions.key = fs.readFileSync('./certificates/privkey.pem','ascii')
SMTPServerOptions.cert = fs.readFileSync('./certificates/cert.pem','ascii')
}
//creating new SMTP object
const server = new SMTPServer(SMTPServerOptions);
server.on('error', err => {
error(err)
throw err
});
server.listen(conf.server_port);
Was able to solve this by commenting some parts of the code in the nodemailer smtp-server module. Just posting here so that it would help others who are seeking the answer for the same.
Some SMTP clients like the one which I used do not wait for the server response after the connection and sends the EHLO or HELO command to the server. From the source code of the module, these clients are treated as early talkers and the connection is blocked to avoid spamming.
Commenting the timeout function and emitting connectionReady() event immediately solved the problem.
/**
* Initiates the connection. Checks connection limits and reverse resolves client hostname. The client
* is not allowed to send anything before init has finished otherwise 'You talk too soon' error is returned
*/
init() {
// Setup event handlers for the socket
this._setListeners(() => {
// Check that connection limit is not exceeded
if (this._server.options.maxClients && this._server.connections.size > this._server.options.maxClients) {
return this.send(421, this.name + ' Too many connected clients, try again in a moment');
}
// Keep a small delay for detecting early talkers
//setTimeout(() => this.connectionReady(), 100);
// no need to detect the early talkers
this.connectionReady();
});
}
Also disable the reverse lookup if it is taking time.
// disabling the reverse lookup which will solve 'you talk so soon problem'
this.options.disableReverseLookup = true;
I'm trying to connect with signalr hub, but I'm getting the following error in javascript:
WebSocket connection to 'ws://dev:777/signalr/connect?transport=webSockets&clientProtocol=1.5&connectionToken=%2BRUC9XodaU4R3Wn3BSLfhZXxLqeLj9fp4XlLJSsxrc36dFuEo6O9GOIGYMdsgSeswY2DTzzJe9qCe9JnqgjwusbYROxjkY%2B6d9FD4MVpox4FLEqNzCF5Y%2BOqrY5ndNs%2FRl7aOoKIYelpGmerXj4mdw%3D%3D&connectionData=%5B%7B%22name%22%3A%22machinehub%22%7D%5D&tid=5' failed: Error during WebSocket handshake: Unexpected response code: 504
and then in console
Could not connect. Invocation of StartMachine failed. Error: No transport could be initialized successfully. Try specifying a different transport or none at all for auto initialization.
I'm using such code to invoke my method from hub which:
self.Run = function (action, parameters, callbacks) {
try {
var connection = $.hubConnection();
connection.logging = self.Debug;
var hub = connection.createHubProxy(self.Name);
registerConnectionEvents(connection);
registerEvents(hub, callbacks);
connection.start({ transport: ['webSockets'] })
.done(function () {
self.debug("Now connected!");
hub.invoke.apply(hub, $.merge([action], parameters)).fail(function (error) {
var msg = 'Invocation of ' + action + ' failed. ' + error;
self.debug(msg);
});
})
.fail(function (error) {
var msg = 'Could not connect. Invocation of ' + action + ' failed. ' + error;
self.debug(msg);
});
return true;
}
When I run my MVC5 app with signalr in Visual Studio everything is fine. After publication to IIS8 on windows Server 2012 it can't connect over web sockets in signal r. I tried to turn off both firewalls for testing but with no success. Can you help me resolve that issue? Of course I read everthing on that page https://learn.microsoft.com/en-us/aspnet/signalr/
In order for SignalR to work properly with WebSocket, you must be sure both client and server support WebSocket. If testing locally works fine, then your browser probably already supports it.
Windows Server 2012 supports SignalR, but you need to be sure websockets feature is enabled:
If this is already enabled, then try recycling your Application Pool (or resetting the IIS).
If recycling/resetting is not sufficient, then you might have something else between the server and the client, like a proxy server or another security layer, like a network firewall (which you might don't have access to it), it could exist in an enterprise environment, or in servers hosted in places like Amazon which might be blocking a port.
please advice someting.
Client code:
var source = new EventSource('/notifications/stream');
source.addEventListener('open', function(e) {
console.log('SSE connected')
}, false);
source.addEventListener('message', function(e) {
alert('yes')
console.log('SSE connected')
}, false);
Server code
// set timeout as high as possible
req.socket.setTimeout(Infinity);
// send headers for event-stream connection
// see spec for more information
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
res.write('\n');
setInterval(function(){
console.log('writing');
res.write("id: " + Date.now() + "\n");
res.write("data: " + '{"message":"hello world"} ' + "\n\n");
}, 1000);
And nothing works... but if I add res.end() after res.write() client fires alert() for one time and server crashes because it already ended the res. I read that it might be antivirus's problem that I client doesn't fire until connection is closed, so I turned off antivirus but it didn't help. So my question is:
Is it code problem or other reason (antivirus)
if it's from antivirus, is it for clients antivirus or server's antivirus problem? (I'm developing on Windows with Nod32 antivirus, if I will deploy on linux, will it help or it depends from client's antivirus)
Is there alternative but websocket (my only need is to push notifications with minimum memory usage)
NodeJS version 0.10.28
Thank You for attention.
Sorry for bad English.
Solved
The problem was in middleware "Compression" that I used in express
Because of the nature of compression this module does not work out of the box with server-sent events. To compress content, a window of the output needs to be buffered up in order to get good compression. Typically when using server-sent events, there are certain block of data that need to reach the client.
You can achieve this by calling res.flush() when you need the data written to actually make it to the client.
I'm using https://oauth.io/ service and I'm a little bit unlucky with finding correct documentation on few things:
Is it possible to unauthorize one or another social network from application? In other words destroy permissions for application to use user's settings of that network.
How do I make google plus oauth work:
There is an example for facebook:
OAuth.popup('facebook', function(err, res) {
if (err) {
// do something with error
}
res.get('/me')
.done(function(data) {
alert('Hello ' + data.name)
})
})
It does work for me but I can't figure out how can I make it work with google+ API. When I change provider to google_plus I manage to get authorization token but I'm not sure how to proceed further because calling res.get('/me') doesn't work ('I suppose /me is only for facebook API'). I've tried lots of different other urls that are for google+ but it seems that because G+ doesn't support CORS request it makes request to local oauthd server like so: options.url = config.oauthd_url + '/request/' + options.oauthio.provider + options.url; network returns that no such endpoint exists.
Please if anyone know how to solve this help me.
Thank you
I just ran into this problem too, and I found a jsfiddle
res.get('/plus/v1/people/me').done(function (me) {
$('#connect').slideUp('fast')
$('#res').html(template({
data: me
})).slideDown('fast')
res.get('/plus/v1/people/me/activities/public').done(function(activities) {
$('#activities').html(activitiesTemplate({
data: activities
}))
});
})