How to Decode a Cookie from the Header of a Websocket Connection Handshake? (Ruby)

How to decode a cookie from the header of a websocket connection handshake? (Ruby)

The answer is to use Rack::Utils.unencode.

I now have this working

Marshal.load(rack_cookie.coder.decode(Rack::Utils.unescape(bakesale.split('--').first))) decodes perfectly to the hash I need, allowing me to extract the user ID. W00t!

Many thanks to User spastorino over at https://github.com/rack/rack/issues/551 for pointing me in the right direction.

Any success with Sinatra working together with EventMachine WebSockets?

Did not try it, but should not be too hard:

require 'em-websocket'
require 'sinatra/base'
require 'thin'

EM.run do
class App < Sinatra::Base
# Sinatra code here
end

EM::WebSocket.start(:host => '0.0.0.0', :port => 3001) do
# Websocket code here
end

# You could also use Rainbows! instead of Thin.
# Any EM based Rack handler should do.
Thin::Server.start App, '0.0.0.0', 3000
end

Also, Cramp has a websocket implementation that works directly with Thin/Rainbows! you might be able to extract, so you won't even need to run the server on another port.

How to Complete a WebSocket Handshake?

Done!

Found the answers from http://blog.honeybadger.io/building-a-simple-websockets-server-from-scratch-in-ruby/ and It's working perfectly!

The code:

public ClientSocket(Socket socket) {
try {
this.socket = socket;
this.input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
this.output = new PrintWriter(socket.getOutputStream());
handshake();
}

private void handshake() {
try {
String line;
String key = "";
while (true) {
line = input.readLine();
if (line.startsWith("Sec-WebSocket-Key: ")) {
key = line.split(" ")[1];
System.out.println("'" + key + "'");
}
if (line == null || line.isEmpty())
break;
}
output.println("HTTP/1.1 101 Switching Protocols");
output.println("Upgrade: websocket");
output.println("Connection: Upgrade");
output.println("Sec-WebSocket-Accept: " + encode(key));
output.println();
output.flush();
} catch (Exception e) {
e.printStackTrace();
}
}

private String encode(String key) throws Exception {
key += "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
byte[] bytes = MessageDigest.getInstance("SHA-1").digest(key.getBytes());
return DatatypeConverter.printBase64Binary(bytes);
}

Now I just have to decode the messages.

Keeping the WebSocket connection alive

The connection is closed each time after handle. You should rather stay there reading incoming data:

# incoming connection
def setup(self):
print "connection established", self.client_address

def handle(self):
while 1:
try:
self.data = self.request.recv(1024).strip()

# incoming message
self.headers = self.headsToDict(self.data.split("\r\n"))

# its a handshake
if "Upgrade" in self.headers and self.headers["Upgrade"] == "websocket":
key = self.headers["Sec-WebSocket-Key"]
accept = b64encode(sha1(key + MAGIC).hexdigest().decode('hex'))
response = "HTTP/1.1 101 Switching Protocols\r\n"
response += "Upgrade: websocket\r\n"
response += "Connection: Upgrade\r\n"
response += "Sec-WebSocket-Accept: "+accept+"\r\n\r\n"
print response
self.request.send(response)
# its a normal message, echo it back
else:
print self.data
self.request.send(self.data)
except:
print "except"
break

Send auth_token for authentication to ActionCable

I managed to send my authentication token as a query parameter.

When creating my consumer in my javascript app, I'm passing the token in the cable server URL like this:

wss://myapp.com/cable?token=1234

In my cable connection, I can get this token by accessing the request.params:

module ApplicationCable
class Connection < ActionCable::Connection::Base
identified_by :current_user

def connect
self.current_user = find_verified_user
logger.add_tags 'ActionCable', current_user.name
end

protected:
def find_verified_user
if current_user = User.find_by(token: request.params[:token])
current_user
else
reject_unauthorized_connection
end
end
end
end

It's clearly not ideal, but I don't think you can send custom headers when creating the websocket.



Related Topics



Leave a reply



Submit