Packages

HBCI/FinTS client library for Elixir.

Current section

Files

Jump to
fintex lib tan flicker_code.ex
Raw

lib/tan/flicker_code.ex

defmodule FinTex.Tan.FlickerCode do
@moduledoc false
alias FinTex.Helper.Checksum
alias FinTex.Helper.Conversion
alias FinTex.Tan.StartCode
alias FinTex.Tan.DataElement
@lc_length_hhd14 3
@lc_length_hhd13 2
import Checksum
import Conversion
defstruct [
:lc,
:start_code,
:data_elements
]
def new(code, version \\ :hhd14) when is_binary(code) and is_atom(version) do
c = code |> clean
len = case version do
:hhd14 -> @lc_length_hhd14
:hhd13 -> @lc_length_hhd13
end
{lc, c} = c |> String.split_at(len)
{lc, _} = Integer.parse(lc)
case String.length(c) == lc do
true -> c |> parse(lc)
false -> code |> new(:hhd13)
end
end
def parse(code, lc) do
{start_code, code} = StartCode.new(code)
{data_element1, code} = DataElement.new(code)
{data_element2, code} = DataElement.new(code)
{data_element3, _} = DataElement.new(code)
%__MODULE__{
lc: lc,
start_code: start_code,
data_elements: [data_element1, data_element2, data_element3]
}
end
def render(m) do
payload = create_payload(m)
payload <> luhn(m) <> xor(payload)
end
defp clean(code) when is_binary(code) do
code = code
|> String.replace(" ", "")
|> String.strip
case ~r/.*CHLGUC\d{4}(.*)CHLGTEXT.*/ |> Regex.run(code) do
nil -> code
matches -> "0" <> (matches |> Enum.at(1))
end
end
defp create_payload(%__MODULE__{start_code: start_code, data_elements: data_elements}) do
payload = StartCode.render_length(start_code) <>
(start_code.control_bytes |> Enum.map(&to_hex/1) |> Enum.join) <>
StartCode.render_data(start_code)
append = for data_element <- data_elements,
length = DataElement.render_length(data_element, start_code.version),
data = DataElement.render_data(data_element)
do
length <> data
end |> Enum.join
payload = payload <> append
lc = (String.length(payload) + 2) |> div(2) |> to_hex(2)
lc <> payload
end
defp luhn(%__MODULE__{start_code: start_code, data_elements: data_elements}) do
luhnsum = (StartCode.render_data(start_code) <>
(start_code.control_bytes |> Enum.map(&to_hex/1) |> Enum.join) <>
(data_elements |> Enum.map(&DataElement.render_data/1) |> Enum.join))
|> String.reverse
|> luhn(16, 10)
10 - luhnsum |> rem(10) |> to_hex(1)
end
end