hawkyre

hawkyre

I need to decode the plug session manually for my websocket server (I used to only have API calls and that worked fine, but now that I need websockets, which don’t work with plug, I have to decode the session cookie without the conn struct). I have managed to get a bitstring, but there seems to be some kind of extra step to go from the bitstring to the map from session key to session value that I’m missing. Here’s the source code I have so far.

These 2 functions are taken almost straight from the plug source code:

defp derive(secret_key_base, key, key_opts) do
  secret_key_base
  |> KeyGenerator.generate(key, key_opts)
end

defp read_raw_cookie(raw_cookie, opts) do
  signing_salt = derive(opts.secret_key_base, opts.signing_salt, opts.key_opts)

  case opts do
    %{encryption_salt: nil} ->
      MessageVerifier.verify(raw_cookie, signing_salt)

    %{encryption_salt: _} ->
      encryption_salt = derive(opts.secret_key_base, opts.encryption_salt, opts.key_opts)
      MessageEncryptor.decrypt(raw_cookie, encryption_salt, signing_salt)
  end
  |> case do
    :error -> nil
    {:ok, result} -> result
  end
end

This is what I do to set up the options for decoding:

opts = %{
  key_opts: [
    length: 64
  ],
  secret_key_base: Application.fetch_env!(:llserver, :session_secret_key_base),
  encryption_salt: Application.fetch_env!(:llserver, :session_encryption_salt),
  signing_salt: Application.fetch_env!(:llserver, :session_signing_salt)
}

cookies = request.headers["cookie"]
ll_cookie = Cookies.decode(cookies)["_ll_session"]
session = read_raw_cookie(ll_cookie, opts)

This returns a session, which in the console prints like this:

<<131, 116, 0, 0, 0, 1, 109, 0, 0, 0, 13, 115, 101, 115, 115, 105, 111, 110, 95,
  116, 111, 107, 101, 110, 109, 0, 0, 0, 72, 100, 99, 56, 48, 49, 97, 100, 102,
  45, 54, 49, 99, 54, 45, 52, 48, 51, 49, 45, 97, 98, ...>>

This is of length 101, however my session keys are 2 concatenated UUIDs like this:

[
  %LLServer.Schema.UserSession{
    __meta__: #Ecto.Schema.Metadata<:loaded, "usersession">,
    id: 1,
    inserted_at: ~N[2023-01-16 13:48:04],
    session: "dc801adf-61c6-4031-ab0c-4fa93012e9d865754857-90d3-4e19-a101-845b4d1b13f5",
    updated_at: ~N[2023-01-16 13:48:04],
    user: #Ecto.Association.NotLoaded<association :user is not loaded>,
    user_id: 1
  }
]

The decryption function seems to work, but I have no idea how to decode that bitstring into the actual session token. The way I put it into the cookies is by calling put_session with a key of :session_token, so I’m assuming that is also saved in the session. How can I retrieve the map just as if I was using Plug.Conn.get_session/1 ?

Showing Posts 1 to 6

voltone

voltone

You need to call :erlang.binary_to_term/1 on that. Or, better: Plug.Crypto.non_executable_binary_to_term(session, [:safe])

hawkyre

hawkyre OP

Thanks a lot! I may do a simple library in the future with all the stuff in here just in case someone else also needs this kind of functionality because it feels weird to not see it already solved.

LostKobrakai

LostKobrakai

All of that code is in plug, so not sure why you feel this is “not solved”. It’s not really clear what you’re doing, but there’s reasons why cookies (and therefore sessioon data) are not just exposed to channels (over websockets) in phoenix – these cannot be properly secured.

Phoenix.Endpoint — Phoenix v1.7.0-rc.2 shows a (seemingly new) session option, which could allow you to access session data when using a CSRF token on the websocket request, which works around those security concerns.

mtrudel

mtrudel

Creator of Bandit

You may want to take a look at the WebSock & WebSockAdapter libraries, along with the new upgrade_adapter/3 function added in Plug 1.14. This is the stack that Phoenix is based on as of 1.7, and comprises a fully open standard WebSocket support in both Bandit and Cowboy web servers.

For what you’re looking to do, you’d want to grab the relevant parts of the Plug.Conn request as part of your HTTP handler for your WebSocket upgrade, and then pass those to your WebSock implementation as the second element of the arg tuple to upgrade_adapter/3. Your WebSock implementation will then see those values as the value to its init/1 call.

Howto docs are a little bit sparse at the moment, but some of the test servers in the Bandit test suite (such as this one) should probably be pretty instructive.

hawkyre

hawkyre OP

I’m not using phoenix, and I’m just using this in the initial connection to the websocket route, not for sending messages once the websocket connection has been established.

hawkyre

hawkyre OP

Oh hey that looks pretty interesting; I’ll definitely check it out. Thanks!

— All posts loaded —

Where Next? Top

Trending in Questions Top

stjefim
Hello! Suppose you are building workflow (order / task / payment) processing system with the following requirements: Each workflow con...
New
jonnycharles
I’m in search of an Elixir library that offers PDF generation capabilities similar to Ruby’s Prawn. While there have been discussions abo...
New
spammy
I’m looking to build a personal workflow to quickly deploy web applications written in elixir/phoenix, for local consumption (ie not on t...
New
Blokh
Hey guys, I’ve got a huge CSV ( around 10 GB ) that needs to be processed hourly Do you guys have any suggestions what is the best prac...
New
dli
Before I dive in myself, did anyone successfully sprinkle Hologram into their existing LiveView app? Looking for hints regarding: Addi...
New
roeland
Kia ora, We have been using elixir-google-api to connect to Google Drive. However, with the updates to Tesla due to CVEs this is now bro...
New
subsaharancoder
I’ve followed the Phoenix LiveView file upload code here Uploads — Phoenix LiveView v1.0.0-rc.7 and so far everything works just fine wit...
New

Other Trending Topics Top

JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
mcass19
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge &amp; Solve. They are GUI (Emerge) and State management (S...
New
ausimian
Emily is an Elixir library that runs Nx computations on Apple’s MLX. Install it as the default Nx backend and Nx, defn, Axon, Nx.Serving,...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews