Skip to content

Commit

Permalink
fix atom atack and move authorized_fields, required_fields to top
Browse files Browse the repository at this point in the history
  • Loading branch information
shahryarjb committed Nov 3, 2023
1 parent 7fa3263 commit 815001f
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 35 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
# Changelog for MishkaDeveloperTools 0.1.2

---
- [ ] Solving the problem of creating extra `atom` in case of a mistake or an attack on the system. It could be a `security` issue, please update.
---

- [x] Add allowed parent domain core key `Enum` derive style
- [x] Add allowed parent domain core key `either` derive style
- [x] Add allowed parent domain core key `equal` derive style
- [x] Add allowed parent domain core key `custom` derive style
- [x] Add driver for accepting `custom` function
- [x] Add status to auto core key if the data of key exists do not create auto value
- [x] Add Conditional field structure `macro` (**Multiple states of a field**)
- [ ] Add driver for accepting JSON
- [ ] Add Conditional field structure `macro` (**Multiple states of a field**)
- [ ] Add driver for making JSON outputs
- [ ] Add derives caller inside parent module
- [ ] Add Supporting new `Typespecs` for `list(struct())` and previous one `struct()`
Expand Down
15 changes: 15 additions & 0 deletions lib/helper/derive/parser.ex
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ defmodule MishkaDeveloperTools.Helper.Derive.Parser do
_e -> nil
end

def convert_to_atom_map({:error, _, _, _} = error), do: error

def convert_to_atom_map({:ok, map}) when is_map(map), do: convert_to_atom_map(map)

def convert_to_atom_map(map) when is_map(map) do
for {key, value} <- map, into: %{}, do: {convert_key(key), convert_value(value)}
end
Expand Down Expand Up @@ -98,4 +102,15 @@ defmodule MishkaDeveloperTools.Helper.Derive.Parser do
def is_data?(%{data: data, errors: errors}) do
Enum.all?(Keyword.keys(errors), &(&1 in Keyword.keys(data)))
end

@doc false
def map_keys(map_data, keys) when is_map(map_data) do
case List.first(Map.keys(map_data)) do
nil -> keys
data when is_atom(data) -> keys
data when is_binary(data) -> Enum.map(keys, &Atom.to_string(&1))
end
end

def map_keys(_map, keys), do: keys
end
68 changes: 35 additions & 33 deletions lib/macros/guarded_struct.ex
Original file line number Diff line number Diff line change
Expand Up @@ -1400,15 +1400,15 @@ defmodule GuardedStruct do
fields = h |> Enum.map(&elem(&1, 0))
conditionals = Enum.at(t, 7)

Parser.convert_to_atom_map(attrs)
attrs
|> before_revaluation(key)
|> authorized_fields(fields, authorized)
|> required_fields(enforces)
|> Parser.convert_to_atom_map()
|> auto_core_key(core_keys, type)
|> domain_core_key()
|> on_core_key(attrs)
|> from_core_key(attrs)
# TODO: shift to top
|> authorized_fields(fields, authorized)
|> required_fields(enforces)
|> conditional_fields_validating(conditionals, type, key, attrs)
|> sub_fields_validating(fields, module, external, attrs, key, type)
|> fields_validating(validator, module)
Expand All @@ -1423,15 +1423,39 @@ defmodule GuardedStruct do
defp before_revaluation(attrs, [:root]), do: attrs

defp before_revaluation(attrs, key) when is_list(key) do
data = get_in(attrs, key)
data = get_in(attrs, Parser.map_keys(attrs, key))
if is_map(data), do: data, else: Map.new([{:bad_parameters, data}])
end

defp before_revaluation(attrs, key) do
data = Map.get(attrs, key)
data = Map.get(attrs, Parser.map_keys(attrs, key))
if is_map(data), do: data, else: Map.new([{:bad_parameters, data}])
end

@doc false
def authorized_fields(attrs, fields, authorized) do
case check_authorized_fields(attrs, fields, authorized) do
{_, true, _} -> {:ok, attrs}
{_, false, filtered} -> {:error, :authorized_fields, filtered, :halt}
end
end

@doc false
def required_fields({:ok, attrs}, enforces) do
with missing_keys <- Enum.reject(Parser.map_keys(attrs, enforces), &Map.has_key?(attrs, &1)),
{:missing_keys, true, _missing_keys} <-
{:missing_keys, Enum.empty?(missing_keys), missing_keys} do
{:ok, attrs}
else
{:missing_keys, false, missing_keys} ->
{:error, :required_fields, missing_keys, :halt}
end
end

def required_fields({:error, _, _, :halt} = error, _), do: error

defp auto_core_key({:error, _, _, :halt} = error, _, _), do: error

defp auto_core_key(attrs, core_keys, type) do
reduce_attrs =
Enum.filter(core_keys, fn {_key, %{type: type, values: _}} -> type == :auto end)
Expand All @@ -1458,6 +1482,8 @@ defmodule GuardedStruct do
{reduce_attrs, core_keys}
end

defp domain_core_key({:error, _, _, :halt} = error), do: error

defp domain_core_key({attrs, core_keys}) do
domain_parameters_errors =
Enum.map(core_keys, fn
Expand All @@ -1479,7 +1505,7 @@ defmodule GuardedStruct do
else: {:error, :domain_parameters, domain_parameters_errors, :halt}
end

defp on_core_key({:error, _, _, _} = error, _full_attrs), do: error
defp on_core_key({:error, _, _, :halt} = error, _full_attrs), do: error

defp on_core_key({:ok, attrs, core_keys}, full_attrs) do
dependent_keys_errors = check_dependent_keys(attrs, core_keys, full_attrs)
Expand All @@ -1489,7 +1515,7 @@ defmodule GuardedStruct do
else: {:error, :dependent_keys, dependent_keys_errors, :halt}
end

defp from_core_key({:error, _, _, _} = error, _full_attrs), do: error
defp from_core_key({:error, _, _, :halt} = error, _full_attrs), do: error

defp from_core_key({:ok, attrs, core_keys}, full_attrs) do
reduce_attrs =
Expand All @@ -1508,30 +1534,6 @@ defmodule GuardedStruct do
{:ok, reduce_attrs}
end

@doc false
def authorized_fields({:ok, attrs}, fields, authorized) do
case check_authorized_fields(attrs, fields, authorized) do
{_, true, _} -> {:ok, attrs}
{_, false, filtered} -> {:error, :authorized_fields, filtered, :halt}
end
end

def authorized_fields({:error, _, _, :halt} = error, _, _), do: error

@doc false
def required_fields({:ok, attrs}, enforces) do
with missing_keys <- Enum.reject(enforces, &Map.has_key?(attrs, &1)),
{:missing_keys, true, _missing_keys} <-
{:missing_keys, Enum.empty?(missing_keys), missing_keys} do
{:ok, attrs}
else
{:missing_keys, false, missing_keys} ->
{:error, :required_fields, missing_keys, :halt}
end
end

def required_fields({:error, _, _, :halt} = error, _), do: error

defp conditional_fields_validating({:error, _, _, :halt} = error, _, _, _, _), do: error

defp conditional_fields_validating({:ok, attrs}, conditionals, type, key, full_attrs) do
Expand Down Expand Up @@ -2047,7 +2049,7 @@ defmodule GuardedStruct do
{:authorized_fields, true, []}

true ->
filtered = Enum.filter(Map.keys(attrs), &(&1 not in fields))
filtered = Enum.filter(Map.keys(attrs), &(&1 not in Parser.map_keys(attrs, fields)))
{:authorized_fields, length(filtered) == 0, filtered}
end
end
Expand Down
2 changes: 1 addition & 1 deletion test/guarded_struct_test.exs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
defmodule MishkaDeveloperToolsTest.GuardedStructTest do
use ExUnit.Case, async: true
alias MishkaDeveloperTools.Helper.Derive.ValidationDerive
############## (▰˘◡˘▰) GuardedStructTest Data (▰˘◡˘▰) ##############
############# (▰˘◡˘▰) GuardedStructTest Data (▰˘◡˘▰) ##############
# Store the bytecode so we can get information from it.
{:module, _name, bytecode, _exports} =
defmodule TestStruct do
Expand Down

0 comments on commit 815001f

Please sign in to comment.