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
?