Current section

Files

Jump to
blossom lib blossom controllers otp_codes.ex
Raw

lib/blossom/controllers/otp_codes.ex

defmodule Blossom.Controllers.OtpCodes do
alias Blossom.Controllers.OtpCodes
alias KilnCore.Utils
def random_code(settings) do
symbols = Enum.to_list(Enum.concat(?A..?Z, ?0..?9))
count = Enum.count(symbols)
for _ <- 1..settings[:length],
into: "",
do: <<Enum.at(symbols, :crypto.strong_rand_range(count))>>
end
def put_expiration(params, settings) do
kind = String.to_atom(Map.get(params, "kind", ""))
expiration = Keyword.get(settings[:expiration], kind, 3600)
Map.put(params, "expiration", System.os_time(:second) + expiration)
end
def new(params, user, ctx) do
settings = ctx[:settings].otp_settings(params["realm"])
params
|> Map.put("code", OtpCodes.random_code(settings))
|> OtpCodes.put_expiration(settings)
|> ctx[:model].new(user)
end
def check_expiration(outcome) do
case outcome do
[code] ->
if code.expiration >= System.os_time(:second) do
{:ok, code}
else
{:error, :expired_code}
end
[] ->
{:error, :invalid_code}
end
end
def clean_code(outcome, code, model) do
case outcome do
{:ok, otp_code} ->
model.delete(otp_code.code, :system)
{:ok, otp_code}
{:error, _} = error ->
model.delete(code, :system)
error
end
end
def verify(params, ctx) do
case params do
%{"code" => code} ->
params
|> ctx[:model].get(:system)
|> OtpCodes.check_expiration()
|> OtpCodes.clean_code(code, ctx[:model])
_ ->
{:error, :unprocessable}
end
end
defmacro __using__(opts \\ []) do
quote do
use KilnCore.Controller, unquote(opts)
@settings Utils.option_or_mod_replace(
@caller,
unquote(opts),
:settings,
Settings,
2
)
@ctx [model: @model, settings: @settings]
def new(params, user, _opts) do
OtpCodes.new(params, user, @ctx)
end
def verify(params, _user) do
OtpCodes.verify(params, @ctx)
end
end
end
end