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])

Where Next?

Popular in Questions Top

gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
pgiesin
This should be a simple problem but I just can’t seem to figure it out. I have a standalone Elixir app that won’t find the database. Dep...
New
script
If I have a string “1000 cfu/ml” . I want to remove the characters and / and space . So the string is like this "1000" What is the ...
New
Phillipp
Hey, I have a NanoPi-M3 and try to install Elixir on their Ubuntu image. I followed the Raspberry Pi installation instructions from the ...
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
kostonstyle
Hi all I want to have a unix time, from the current time plus 1 hour. DateTime.now + 1 hour How to get it in elixir? Thanks
New
beno
I will often find my self writing things similar to: case some_value do nil -&gt; something() "" -&gt; something() _ -&gt; someth...
New
idi527
I’ve been re-reading swift book again and noticed that multiline strings there don’t have a trailing line break, unlike in elixir iex(2)...
New

Other popular topics Top

JakeBecker
TL;DR: I’ve just released an implementation of Microsoft’s IDE-independent Language Server Protocol for Elixir. It adds language support ...
1140 51847 244
New
quazar
How to set Jason to encode all fields in ecto schema, I don’t care about security and implementing only is taking long list of attributes...
New
danschultzer
None of the current solutions worked well for me, so I went ahead and built a user management system from scratch. This project took far...
548 27727 240
New
chensan
I have a User schema with a :from_id field set to type :string: defmodule TweetBot.Repo.Migrations.CreateUsers do use Ecto.Migration ...
New
rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list....
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? https://hexdocs.pm/ecto/Ecto.Repo.h...
New
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
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
josevalim
Hi everyone, One of the features added to Elixir early on to help integration with Erlang code was the idea of overridable function defi...
New

We're in Beta

About us Mission Statement