Rule CRUD coming along ...

This commit is contained in:
Jamil Bou Kheir
2020-05-14 23:34:18 -05:00
parent 18e4d41a22
commit a18b2fe212
17 changed files with 122 additions and 56 deletions

View File

@@ -52,6 +52,14 @@ defmodule FgHttp.Devices do
"""
def get_device!(id), do: Repo.get!(Device, id)
def get_device!(id, with_rules: true) do
Repo.one(
from d in Device,
where: d.id == ^id,
preload: :rules
)
end
@doc """
Creates a device.

View File

@@ -6,13 +6,15 @@ defmodule FgHttp.Devices.Device do
use Ecto.Schema
import Ecto.Changeset
alias FgHttp.{Rules.Rule, Users.User}
schema "devices" do
field :name, :string
field :public_key, :string
field :user_id, :id
field :last_ip, :map
has_many :rules, FgHttp.Rules.Rule
has_many :rules, Rule
belongs_to :user, User
timestamps()
end

View File

@@ -0,0 +1,18 @@
import EctoEnum
# We only allow dropping or accepting packets for now
defenum(RuleActionEnum, :action, [:drop, :accept])
# See http://ipset.netfilter.org/iptables.man.html
defenum(RuleProtocolEnum, :protocol, [
:all,
:tcp,
:udp,
:udplite,
:icmp,
:icmpv6,
:esp,
:ah,
:sctp,
:mh
])

View File

@@ -17,6 +17,10 @@ defmodule FgHttp.Rules do
[%Rule{}, ...]
"""
def list_rules(device_id) do
Repo.all(from r in Rule, where: r.device_id == ^device_id, select: "*")
end
def list_rules do
Repo.all(Rule)
end

View File

@@ -6,13 +6,17 @@ defmodule FgHttp.Rules.Rule do
use Ecto.Schema
import Ecto.Changeset
schema "rules" do
field :destination, :map
field :enabled, :boolean, default: false
field :port, :string
field :protocol, :string
alias FgHttp.{Devices.Device}
belongs_to :device, FgHttp.Devices.Device
schema "rules" do
field :destination, EctoNetwork.INET
field :action, RuleActionEnum, default: "drop"
field :priority, :integer, default: 0
field :enabled, :boolean, default: true
field :port, :string
field :protocol, RuleProtocolEnum, default: "all"
belongs_to :device, Device
timestamps()
end
@@ -20,7 +24,7 @@ defmodule FgHttp.Rules.Rule do
@doc false
def changeset(rule, attrs) do
rule
|> cast(attrs, [:destination, :port, :protocol, :enabled])
|> validate_required([:destination, :enabled])
|> cast(attrs, [:device_id, :priority, :action, :destination, :port, :protocol, :enabled])
|> validate_required([:device_id, :priority, :action, :destination, :protocol, :enabled])
end
end

View File

@@ -6,8 +6,10 @@ defmodule FgHttp.Sessions.Session do
use Ecto.Schema
import Ecto.Changeset
alias FgHttp.{Users.User}
schema "sessions" do
field :user_id, :id
belongs_to :user, User
timestamps()
end

View File

@@ -6,12 +6,17 @@ defmodule FgHttp.Users.User do
use Ecto.Schema
import Ecto.Changeset
alias FgHttp.{Devices.Device, Sessions.Session}
schema "users" do
field :email, :string
field :confirmed_at, :utc_datetime
field :last_signed_in_at, :utc_datetime
field :password_digest, :string
has_many :devices, Device
has_many :sessions, Session
timestamps()
end

View File

@@ -9,8 +9,7 @@ defmodule FgHttpWeb.RuleController do
plug FgHttpWeb.Plugs.Authenticator
def index(conn, %{"device_id" => device_id}) do
device = Devices.get_device!(device_id)
device = Devices.get_device!(device_id, with_rules: true)
render(conn, "index.html", device: device, rules: device.rules)
end

View File

@@ -12,5 +12,9 @@
</li>
</ul>
<span><%= link "Edit", to: Routes.device_path(@conn, :edit, @device) %></span>
<span><%= link "Back", to: Routes.device_path(@conn, :index) %></span>
<p>
<%= link "Show Rules for This Device", to: Routes.device_rule_path(@conn, :index, @device) %>
</p>
<p><%= link "Edit", to: Routes.device_path(@conn, :edit, @device) %></p>
<p><%= link "Back", to: Routes.device_path(@conn, :index) %></p>

View File

@@ -1,27 +1,41 @@
<%= form_for @changeset, @action, fn f -> %>
<%= form_for @changeset, @action, [class: "black-80"], fn f -> %>
<%= if @changeset.action do %>
<div>
<div class="mt4 measure">
<p>Oops, something went wrong! Please check the errors below.</p>
</div>
<% end %>
<%= label f, :destination %>
<%= text_input f, :destination %>
<%= error_tag f, :destination %>
<div class="mt4 measure">
<%= label f, :destination, class: "f6 b db mb2" %>
<%= text_input f, :destination, class: "input-reset ba b--black-20 pa2 mb2 db w-100" %>
<%= error_tag f, :destination %>
</div>
<%= label f, :port %>
<%= text_input f, :port %>
<%= error_tag f, :port %>
<div class="mt4 measure">
<%= label f, :port, class: "f6 b db mb2" %>
<%= text_input f, :port, class: "input-reset ba b--black-20 pa2 mb2 db w-100" %>
<%= error_tag f, :port %>
</div>
<%= label f, :protocol %>
<%= text_input f, :protocol %>
<%= error_tag f, :protocol %>
<div class="mt4 measure">
<%= label f, :protocol, class: "f6 b db mb2" %>
<%= text_input f, :protocol, class: "input-reset ba b--black-20 pa2 mb2 db w-100" %>
<%= error_tag f, :protocol %>
</div>
<%= label f, :enabled %>
<%= checkbox f, :enabled %>
<%= error_tag f, :enabled %>
<div class="mt4 measure">
<%= label f, :priority, class: "f6 b db mb2" %>
<%= text_input f, :priority, class: "input-reset ba b--black-20 pa2 mb2 db w-100" %>
<%= error_tag f, :priority %>
</div>
<div>
<div class="mt4 measure">
<%= label f, :enabled, class: "f6 b db mb2" %>
<%= checkbox f, :enabled %>
<%= error_tag f, :enabled %>
</div>
<div class="mt4 measure">
<%= submit "Save" %>
</div>
<% end %>

View File

@@ -1,23 +1,21 @@
<h1>Listing Rules</h1>
<h1>Listing Rules for Device <%= @device.name %></h1>
<table>
<thead>
<tr>
<th>Destination</th>
<th>Port</th>
<th>Protocol</th>
<th>Enabled</th>
<table class="collapse ba br2 b--black-10 pv2 ph3 mt4">
<tbody>
<tr class="striped--near-white">
<th class="pv2 ph3 tl f6 fw6 ttu">Destination</th>
<th class="pv2 ph3 tl f6 fw6 ttu">Port</th>
<th class="pv2 ph3 tl f6 fw6 ttu">Protocol</th>
<th class="pv2 ph3 tl f6 fw6 ttu">Enabled</th>
<th></th>
</tr>
</thead>
<tbody>
<%= for rule <- @rules do %>
<tr>
<td><%= rule.destination %></td>
<td><%= rule.port %></td>
<td><%= rule.protocol %></td>
<td><%= rule.enabled %></td>
<tr class="striped--near-white">
<td class="pv2 ph3 tl f6 fw6 ttu"><%= rule.destination %></td>
<td class="pv2 ph3 tl f6 fw6 ttu"><%= rule.port %></td>
<td class="pv2 ph3 tl f6 fw6 ttu"><%= rule.protocol %></td>
<td class="pv2 ph3 tl f6 fw6 ttu"><%= rule.enabled %></td>
<td>
<span><%= link "Show", to: Routes.rule_path(@conn, :show, rule) %></span>
@@ -30,5 +28,5 @@
</table>
<p>
<%= link "New Rule", to: Routes.rule_path(@conn, :new, @device) %>
<%= link "New Rule", to: Routes.device_rule_path(@conn, :new, @device) %>
</p>

View File

@@ -1,5 +1,5 @@
<h1>New Rule</h1>
<h1>New Rule for Device <%= @device.name %></h1>
<%= render "form.html", Map.put(assigns, :action, Routes.rule_path(@conn, :create, @device)) %>
<%= render "form.html", Map.put(assigns, :action, Routes.device_rule_path(@conn, :create, @device)) %>
<span><%= link "Back", to: Routes.rule_path(@conn, :index, @device) %></span>
<span><%= link "Back", to: Routes.device_rule_path(@conn, :index, @device) %></span>

View File

@@ -41,6 +41,8 @@ defmodule FgHttp.MixProject do
{:phoenix_pubsub, "~> 2.0"},
{:phoenix_ecto, "~> 4.0"},
{:ecto_sql, "~> 3.1"},
{:ecto_enum, "~> 1.4.0"},
{:ecto_network, "~> 1.3.0"},
{:postgrex, ">= 0.0.0"},
{:phoenix_html, "~> 2.11"},
{:phoenix_live_reload, "~> 1.2", only: :dev},

View File

@@ -6,7 +6,7 @@ defmodule FgHttp.Repo.Migrations.CreateDevices do
add :name, :string
add :public_key, :string
add :last_ip, :inet
add :user_id, references(:users, on_delete: :delete_all)
add :user_id, references(:users, on_delete: :delete_all), null: false
timestamps()
end

View File

@@ -2,12 +2,17 @@ defmodule FgHttp.Repo.Migrations.CreateRules do
use Ecto.Migration
def change do
RuleActionEnum.create_type()
RuleProtocolEnum.create_type()
create table(:rules) do
add :destination, :inet
add :port, :string
add :protocol, :string
add :protocol, RuleProtocolEnum.type(), default: "all", null: false
add :action, RuleActionEnum.type(), default: "drop", null: false
add :priority, :integer, default: 0, null: false
add :enabled, :boolean, default: false, null: false
add :device_id, references(:devices, on_delete: :delete_all)
add :port, :string
add :device_id, references(:devices, on_delete: :delete_all), null: false
timestamps()
end

View File

@@ -23,9 +23,9 @@ Repo.transaction(fn ->
user_id: user.id
})
{:ok, rule} =
{:ok, _rule} =
FgHttp.Rules.create_rule(%{
destination: %Postgrex.INET{address: {0, 0, 0, 0}, netmask: 0},
device_id: device.id
device_id: device.id,
destination: %Postgrex.INET{address: {0, 0, 0, 0}, netmask: 0}
})
end)

View File

@@ -7,6 +7,7 @@
"db_connection": {:hex, :db_connection, "2.2.2", "3bbca41b199e1598245b716248964926303b5d4609ff065125ce98bcd368939e", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}], "hexpm", "642af240d8a8affb93b4ba5a6fcd2bbcbdc327e1a524b825d383711536f8070c"},
"decimal": {:hex, :decimal, "1.8.1", "a4ef3f5f3428bdbc0d35374029ffcf4ede8533536fa79896dd450168d9acdf3c", [:mix], [], "hexpm", "3cb154b00225ac687f6cbd4acc4b7960027c757a5152b369923ead9ddbca7aec"},
"ecto": {:hex, :ecto, "3.4.4", "a2c881e80dc756d648197ae0d936216c0308370332c5e77a2325a10293eef845", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "cc4bd3ad62abc3b21fb629f0f7a3dab23a192fca837d257dd08449fba7373561"},
"ecto_enum": {:hex, :ecto_enum, "1.4.0", "d14b00e04b974afc69c251632d1e49594d899067ee2b376277efd8233027aec8", [:mix], [{:ecto, ">= 3.0.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "> 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:mariaex, ">= 0.0.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "8fb55c087181c2b15eee406519dc22578fa60dd82c088be376d0010172764ee4"},
"ecto_network": {:hex, :ecto_network, "1.3.0", "1e77fa37c20e0f6a426d3862732f3317b0fa4c18f123d325f81752a491d7304e", [:mix], [{:ecto_sql, ">= 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:phoenix_html, ">= 0.0.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.14.0", [hex: :postgrex, repo: "hexpm", optional: false]}], "hexpm", "053a5e46ef2837e8ea5ea97c82fa0f5494699209eddd764e663c85f11b2865bd"},
"ecto_sql": {:hex, :ecto_sql, "3.4.3", "c552aa8a7ccff2b64024f835503b3155d8e73452c180298527fbdbcd6e79710b", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.4.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.3.0 or ~> 0.4.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.0", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ec9e59d6fa3f8cfda9963ada371e9e6659167c2338a997bd7ea23b10b245842b"},
"file_system": {:hex, :file_system, "0.2.8", "f632bd287927a1eed2b718f22af727c5aeaccc9a98d8c2bd7bff709e851dc986", [:mix], [], "hexpm", "97a3b6f8d63ef53bd0113070102db2ce05352ecf0d25390eb8d747c2bde98bca"},