Current section
Files
Jump to
Current section
Files
lib/session.ex
defmodule Bouncer.Session do
@moduledoc """
A library of functions used to work with session data.
"""
alias Plug.Conn
@doc """
Makes the adapter specified in the environment configuration available.
"""
def adapter, do: Application.get_env(:bouncer, :adapter)
@doc """
Creates a session for a given user and saves it to the session store. Returns
the session token which will be used as the API authorization token.
"""
def create(conn, user) do
Poison.encode!(user)
|> save(Phoenix.Token.sign(conn, "user", user.id))
end
@doc """
Saves session data to the session store using a key.
"""
def save(data, key), do: adapter.save(data, key)
@doc """
Retrieves session data given a token (key) and assigns it to the connection.
"""
def get(conn, token) do
case Phoenix.Token.verify(conn, "user", token) do
{ :ok, id } ->
conn = Conn.assign(conn, :user_token, token)
token
|> adapter.get
|> parse_data
|> verify_user_match(id)
_ -> { :error, "Could not verify token" }
end
end
@doc """
Parses JSON session data retrieved from the store into a map.
## Examples
iex> Bouncer.Session.parse_data({ :ok, ~s({"id": 1}) })
{ :ok, %{id: 1} }
iex> Bouncer.Session.parse_data({ :error, nil })
{ :error, nil }
iex> Bouncer.Session.parse_data({ :ok, "" })
{ :error, :invalid }
"""
def parse_data({ status, response }) do
case status do
:ok ->
case Poison.Parser.parse response, keys: :atoms! do
{ :ok, data} -> { :ok, data }
{ status, response } -> { :error, response }
end
status -> { status, response }
end
end
@doc """
Verifies that the ID deciphered from the received token matches the ID in the
session data.
## Examples
iex> Bouncer.Session.verify_user_match({ :ok, %{id: 1} }, 1)
{ :ok, %{id: 1} }
iex> Bouncer.Session.verify_user_match({ :ok, %{id: 2} }, 1)
{ :error, "Token ID does not match session data ID" }
iex> Bouncer.Session.verify_user_match({ :error, nil }, 1)
{ :error, nil }
"""
def verify_user_match({ status, response }, id) do
case status do
:ok ->
if Map.has_key?(response, :id) && response.id === id do
{ :ok, response }
else
{ :error, "Token ID does not match session data ID"}
end
status -> { status, response }
end
end
@doc """
Destroys a session by removing session data from the store.
"""
def destroy(key), do: adapter.delete(key)
end