Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 102 additions & 0 deletions lib/drab/coder.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
defmodule Drab.Coder do
@moduledoc """
Provides various encoders/decoders to store values in the string.

Example:

<% {:ok, encoded_value} = Drab.Coder.encode(%{question: "foo", answer: 42}) %>
<button drab='click:check_answer("<%= encoded_value %>")'>Check answer</button>

defhandler check_answer(socket, sender, value) do
{:ok, decoded_value} = Drab.Coder.decode(value)

question = decoded_value[:question]
answer = decoded_value[:answer]
end

The default encoder is `Drab.Coder.Cipher`, which encrypts any value and returns the base-64
encoded string. You may change the default encoder with:

config :drab, default_encoder: Drab.Coder.String

Each encoder has two pairs of functions:
* `encode/1` / `decode/1`, returning tuple `{:ok, result}`
* `encode!/1` / `decode!/1`, returning the result

The result of encode functions is always a string. The argument might be restricted to string
(`Drab.Coder.URL`, `Drab.Coder.Base64`). Other encoders takes any valid term as an argument.

The argument of decode functions is always a string.

Available encoders:
* `Drab.Coder.URL` - urlencode, encodes only string
* `Drab.Coder.Base64` - simple base-64, encodes string only (no encryption)
* `Drab.Coder.String` - encodes any term to string, not ciphered
* `Drab.Coder.Cipher` - encodes any term to an encrypted string (default)

You may use the encoders individually, they expose the same API as `Drab.Coder`:

iex> {:ok, encoded} = Drab.Coder.String.encode(%{forty_two: 42})
iex> Drab.Coder.String.decode(encoded)
{:ok, %{forty_two: 42}}

It is used in the other part of the application, for example in `Drab.Browser.set_cookie/3`:

set_cookie(socket, "my_cookie", "42", encode: true) # use default encoder
set_cookie(socket, "my_cookie", "result: 42", encode: Drab.Coder.URL)
"""

@type return :: {:ok, String.t()} | {:error, String.t()}

@doc """
Encodes term to the string.

Returns:
* `{:ok, string}`
* `{:error, reason}`

iex> {:ok, encoded} = Drab.Coder.encode(%{forty_two: 42})
iex> is_binary(encoded)
true
"""
@spec encode(term) :: Drab.Coder.return()
defdelegate encode(term), to: Drab.Config.get(:default_encoder)

@doc """
Bang version of `encode/1`.

Returns string.

iex> encoded = Drab.Coder.encode!(%{forty_two: 42})
iex> is_binary(encoded)
true
"""
@spec encode!(term) :: String.t()
defdelegate encode!(term), to: Drab.Config.get(:default_encoder)

@doc """
Decodes the string, returning the encoded value (any term).

Returns:
* `{:ok, term}`
* `{:error, reason}`

iex> {:ok, encoded} = Drab.Coder.encode(%{forty_two: 42})
iex> Drab.Coder.decode(encoded)
{:ok, %{forty_two: 42}}
"""
@spec decode(String.t()) :: Drab.Coder.return()
defdelegate decode(string), to: Drab.Config.get(:default_encoder)

@doc """
Bang version of `decode/1`.

Returns the term.

iex> encoded = Drab.Coder.encode!(%{forty_two: 42})
iex> Drab.Coder.decode!(encoded)
%{forty_two: 42}
"""
@spec decode!(String.t()) :: term
defdelegate decode!(string), to: Drab.Config.get(:default_encoder)
end
52 changes: 52 additions & 0 deletions lib/drab/coder/base64.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
defmodule Drab.Coder.Base64 do
@moduledoc false

@invalid_argument {:error, "invalid argument; only string is allowed"}

@spec encode(term) :: Drab.Coder.return()
@doc """
Encode string to Base64.

iex> Drab.Coder.Base64.encode("test")
{:ok, "dGVzdA=="}
iex> Drab.Coder.Base64.encode(42)
{:error, "invalid argument; only string is allowed"}
"""
def encode(string) when is_binary(string), do: {:ok, Base.encode64(string)}
def encode(_), do: @invalid_argument

@spec encode!(String.t()) :: String.t()
@doc """
Bang version of encode/1.

iex> Drab.Coder.Base64.encode!("test")
"dGVzdA=="
"""
defdelegate encode!(string), to: Base, as: :encode64

@doc """
Decode string from Base64.

iex> Drab.Coder.Base64.decode("dGVzdA==")
{:ok, "test"}
iex> Drab.Coder.Base64.decode(42)
{:error, "invalid argument; only string is allowed"}
"""
@spec decode(String.t()) :: Drab.Coder.return()
def decode(string) when is_binary(string) do
case Base.decode64(string) do
:error -> {:error, "string is not base-64 encoded"}
result -> result
end
end
def decode(_), do: @invalid_argument

@doc """
Bang version of decode/1

iex> Drab.Coder.Base64.decode!("dGVzdA==")
"test"
"""
@spec decode!(String.t()) :: String.t()
defdelegate decode!(string), to: Base, as: :decode64!
end
59 changes: 59 additions & 0 deletions lib/drab/coder/cipher.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
defmodule Drab.Coder.Cipher do
@moduledoc false

@spec encode(term) :: Drab.Coder.return()
@doc """
Encrypt any term and encode it to Base64.

iex> {:ok, t} = Drab.Coder.Cipher.encode("test")
iex> t != "test"
true
"""
def encode(term) do
term
|> Drab.Live.Crypto.encrypt()
|> Drab.Coder.Base64.encode()
end

@spec encode!(term) :: String.t()
@doc """
Encrypt any term and encode it to Base64.

iex> Drab.Coder.Cipher.encode!("test") != "test"
true
"""
def encode!(term) do
term
|> Drab.Live.Crypto.encrypt()
|> Drab.Coder.Base64.encode!()
end

@spec decode(String.t()) :: Drab.Coder.return()
@doc """
Decrypt and base-64 decode string. Returns term.

iex> {:ok, encoded} = Drab.Coder.Cipher.encode([1,2,3])
iex> Drab.Coder.Cipher.decode(encoded)
{:ok, [1,2,3]}
"""
def decode(string) do
case Drab.Coder.Base64.decode(string) do
{:ok, encrypted} -> {:ok, Drab.Live.Crypto.decrypt(encrypted)}
error -> error
end
end

@spec decode!(String.t()) :: term
@doc """
Decrypt and base-64 decode string. Returns term.

iex> encoded = Drab.Coder.Cipher.encode!(%{a: 1})
iex> Drab.Coder.Cipher.decode!(encoded)
%{a: 1}
"""
def decode!(string) do
string
|> Drab.Coder.Base64.decode!()
|> Drab.Live.Crypto.decrypt()
end
end
59 changes: 59 additions & 0 deletions lib/drab/coder/string.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
defmodule Drab.Coder.String do
@moduledoc false

@spec encode(term) :: Drab.Coder.return()
@doc """
Encrypt any term and encode it to Base64.

iex> {:ok, t} = Drab.Coder.String.encode(1)
iex> t
"g2EB"
"""
def encode(term) do
term
|> :erlang.term_to_binary()
|> Drab.Coder.Base64.encode()
end

@spec encode!(term) :: String.t()
@doc """
Encrypt any term and encode it to Base64.

iex> Drab.Coder.String.encode!("test")
"g20AAAAEdGVzdA=="
"""
def encode!(term) do
term
|> :erlang.term_to_binary()
|> Drab.Coder.Base64.encode!()
end

@spec decode(String.t()) :: Drab.Coder.return()
@doc """
Decrypt and base-64 decode string. Returns term.

iex> {:ok, encoded} = Drab.Coder.String.encode([1,2,3])
iex> Drab.Coder.String.decode(encoded)
{:ok, [1,2,3]}
"""
def decode(string) do
case Drab.Coder.Base64.decode(string) do
{:ok, s} -> {:ok, :erlang.binary_to_term(s)}
error -> error
end
end

@spec decode!(String.t()) :: term
@doc """
Decrypt and base-64 decode string. Returns term.

iex> encoded = Drab.Coder.String.encode!(%{a: 1})
iex> Drab.Coder.String.decode!(encoded)
%{a: 1}
"""
def decode!(string) do
string
|> Drab.Coder.Base64.decode!()
|> :erlang.binary_to_term()
end
end
49 changes: 49 additions & 0 deletions lib/drab/coder/url.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
defmodule Drab.Coder.URL do
@moduledoc false

@invalid_argument {:error, "invalid argument; only string is allowed"}

@spec encode(String.t()) :: Drab.Coder.return()
@doc """
Urlencode given string.

iex> Drab.Coder.URL.encode("test !/ Łódź&?")
{:ok, "test+%21%2F+%C5%81%C3%B3d%C5%BA%26%3F"}
iex> Drab.Coder.URL.encode(42)
{:error, "invalid argument; only string is allowed"}
"""
def encode(string) when is_binary(string), do: {:ok, URI.encode_www_form(string)}

def encode(_), do: @invalid_argument

@spec encode!(String.t()) :: String.t()
@doc """
Urlencode given string.

iex> Drab.Coder.URL.encode!("test !/ Łódź&?")
"test+%21%2F+%C5%81%C3%B3d%C5%BA%26%3F"
"""
defdelegate encode!(string), to: URI, as: :encode_www_form

@spec decode(String.t()) :: Drab.Coder.return()
@doc """
Urldecode the string.

iex> Drab.Coder.URL.decode("test+%21%2F+%C5%81%C3%B3d%C5%BA%26%3F")
{:ok, "test !/ Łódź&?"}
iex> Drab.Coder.URL.decode(42)
{:error, "invalid argument; only string is allowed"}
"""
def decode(string) when is_binary(string), do: {:ok, URI.decode_www_form(string)}

def decode(_), do: @invalid_argument

@spec decode!(String.t()) :: String.t()
@doc """
Urldecode the string.

iex> Drab.Coder.URL.decode!("test+%21%2F+%C5%81%C3%B3d%C5%BA%26%3F")
"test !/ Łódź&?"
"""
defdelegate decode!(string), to: URI, as: :decode_www_form
end
5 changes: 5 additions & 0 deletions lib/drab/config.ex
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ defmodule Drab.Config do

#### :phoenix_channel_options *(default: [])*
An options passed to `use Phoenix.Channel`, for example: `[log_handle_in: false]`.

#### :default_encoder *(default: Drab.Coder.Cipher)
Sets the default encoder/decoder for the various functions, like `Drab.Browser.set_cookie/3`
"""

@doc """
Expand Down Expand Up @@ -277,6 +280,8 @@ defmodule Drab.Config do

def get(:templates_path), do: Application.get_env(:drab, :templates_path, "priv/templates/drab")

def get(:default_encoder), do: Application.get_env(:drab, :default_encoder, Drab.Coder.Cipher)

def get(:live_conn_pass_through) do
Application.get_env(:drab, :live_conn_pass_through, %{
private: %{
Expand Down
8 changes: 8 additions & 0 deletions test/drab/coder_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
defmodule Drab.CoderTest do
use ExUnit.Case, ascync: true
doctest Drab.Coder.Base64
doctest Drab.Coder.URL
doctest Drab.Coder.Cipher
doctest Drab.Coder.String
doctest Drab.Coder
end