jaspervdj / websockets

A Haskell library for creating WebSocket-capable servers
http://jaspervdj.be/websockets
BSD 3-Clause "New" or "Revised" License
406 stars 112 forks source link

Eq instance of Connection #98

Open henrylaxen opened 9 years ago

henrylaxen commented 9 years ago

Dear Jasper,

I don't know if it is possible, but I think it would be really nice to have an Eq instance of Connection. That way I could have [Connection] and be able to move them to different lists based on some test. I'm working around it now by wrapping Connection and using Data.Supply to generate my own Eq instance. Just something to think about in your copious spare time ;-)

skatenerd commented 8 years ago

An Ord instance would be nice too. It's nice to use a Set to track the connections so you can easily add/remove.

mitchellwrosen commented 8 years ago

This can't currently be done in a way that doesn't break backwards compatibility (i.e. introduce some custom monad to track the unique supply), because Connection can't simply derive Eq.

You could use some global-supply hack such as

import Control.Concurrent.MVar
import Control.Concurrent.Supply (Supply)
import qualified Control.Concurrent.Supply as Supply

globalSupply :: MVar Supply
globalSupply = unsafePerformIO (Supply.newSupply >>= newMVar)
{-# NOINLINE globalSupply #-}

freshId :: IO Int
freshId = modifyMVar supply (\s -> 
    let (n, s') = Supply.freshId s
    in pure (s', n))

data Connection = Connection
    { ...
    , connectionId :: Int
    }
jaspervdj commented 8 years ago

Socket actually provides an Eq instance so it might be able to piggyback on top of that.

Alternatively, we can use the 4-tuple (source IP, source port, destination IP, destination port) to uniquely identify the connection as well, but we'd also need to store that info in the Connection datatype. This would be my preferred solution.

fschr commented 8 years ago

Just to be clear, does this mean that with the current state of WebSockets, we're just supposed to trust connections? Is there anyway to uniquely identify users right now?

jaspervdj commented 8 years ago

The correct way to do this is to have the server pass the socket 4-tuples to the websockets library, and then make these available in PendingConnection/Connection. However, some of the Haskell HTTP servers do not support that, so I didn't go through with that implementation for now.

I don't really know what you mean by "trust the connections" though. Users should be identified by implementing proper authentication either over HTTPS or through WebSocket messages.

skatenerd commented 8 years ago

I guess one pattern is to provide a nonce-style token to the user via http, and then identify the websocket connection based on what token they send over.

jaspervdj commented 8 years ago

Well, usually WebSocket apps are part of larger HTTP apps, which already have some sort of authentication system in place using cookies/headers.

Since a WebSocket connection starts out like a normal HTTP request, a great pattern is to use your existing HTTP authentication layer to check the cookies before turning it into a WebSocket connection. This is possible with both the Snap and Yesod backends, and I've personally used this pattern successfully in the past.