hawkyre

hawkyre

Decoding Plug session manually

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 ?

Marked As Solved

voltone

voltone

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

Last Post!

hawkyre

hawkyre

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

Where Next?

Popular in Questions Top

joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
PeterCarter
There are pre-rolled solutions for other frameworks that do work. However, Phoenix does not seem to have these. Have people had good expe...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
svb
Hi! Currently I want to submit a form by pressing the Enter key. However, since my input field is of type “textarea” this is just adds a...
New

Other popular topics Top

electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
Darmani72
If I have a post route which an argument: post /my_post_route/:my_param1, MyController.my_post_handler How would get the post params ...
New
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 44167 214
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
274 42576 114
New

We're in Beta

About us Mission Statement