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 Blossom.Utils
def random_code(opts) do
symbols = Enum.to_list(Enum.concat(?A..?Z, ?0..?9))
count = Enum.count(symbols)
for _ <- 1..opts[:codes_length],
into: "",
do: <<Enum.at(symbols, :crypto.strong_rand_range(count))>>
end
def put_expiration(params, opts) do
kind = String.to_atom(Map.get(params, "kind", ""))
expiration = Keyword.get(opts[:expiration], kind, 3600)
Map.put(params, "expiration", System.os_time(:second) + expiration)
end
def codes_length(config, opts) do
Utils.option_or_key_config(config, opts, :codes_length, 6)
end
def expiration(config, opts) do
defaults = [email_verification: 43200]
Utils.option_or_key_config(config, opts, :codes_expiration, defaults)
end
def codes_opts(opts, otp_app) do
config = Application.get_env(otp_app, Blossom, [])
[
codes_length: OtpCodes.codes_length(config, opts),
expiration: OtpCodes.expiration(config, opts)
]
end
def new(params, user, opts, ctx) do
params
|> Map.put("code", OtpCodes.random_code(opts))
|> OtpCodes.put_expiration(opts)
|> 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, :missing_fields}
end
end
defmacro __using__(opts \\ []) do
quote do
use KilnCore.Controller, unquote(opts)
@opts unquote(opts)
@otp_app KilnCore.Utils.atom_name(@caller)
@ctx [model: @model]
def new(params, user, _opts) do
codes_opts = OtpCodes.codes_opts(@opts, @otp_app)
OtpCodes.new(params, user, codes_opts, @ctx)
end
def verify(params, _user) do
OtpCodes.verify(params, @ctx)
end
end
end
end