<%= label(f, :email, class: "db fw6 lh-copy f6") %>
diff --git a/apps/fg_http/lib/fg_http_web/templates/user/new.html.eex b/apps/fg_http/lib/fg_http_web/templates/user/new.html.eex
index 866217ad0..e4019a9d3 100644
--- a/apps/fg_http/lib/fg_http_web/templates/user/new.html.eex
+++ b/apps/fg_http/lib/fg_http_web/templates/user/new.html.eex
@@ -1,27 +1,36 @@
Sign Up
-<%= form_for @changeset, Routes.user_path(@conn, :new), fn f -> %>
+<%= form_for @changeset, Routes.user_path(@conn, :create), fn f -> %>
<%= if @changeset.action do %>
Oops, something went wrong! Please check the errors below.
<% end %>
-
-
-
-
-
-
-
-
-
-
- <%= submit "Submit" %>
+
+
+ <%= submit "Sign Up", class: "b ph3 pv2 input-reset ba b--black bg-transparent grow pointer f6 dib" %>
+
<% end %>
diff --git a/apps/fg_http/lib/fg_http_web/views/device_view.ex b/apps/fg_http/lib/fg_http_web/views/device_view.ex
index c21ec491f..2963163b4 100644
--- a/apps/fg_http/lib/fg_http_web/views/device_view.ex
+++ b/apps/fg_http/lib/fg_http_web/views/device_view.ex
@@ -1,16 +1,3 @@
defmodule FgHttpWeb.DeviceView do
use FgHttpWeb, :view
- import Ecto.Changeset, only: [traverse_errors: 2]
-
- def aggregated_errors(changeset) do
- traverse_errors(changeset, fn {msg, opts} ->
- Enum.reduce(opts, msg, fn {key, value}, acc ->
- String.replace(acc, "%{#{key}}", to_string(value))
- end)
- end)
- |> Enum.reduce("", fn {key, value}, acc ->
- joined_errors = Enum.join(value, "; ")
- "#{acc}#{key}: #{joined_errors}\n"
- end)
- end
end
diff --git a/apps/fg_http/mix.exs b/apps/fg_http/mix.exs
index 5752d766e..26f933c00 100644
--- a/apps/fg_http/mix.exs
+++ b/apps/fg_http/mix.exs
@@ -46,6 +46,7 @@ defmodule FgHttp.MixProject do
[
{:phoenix, "~> 1.5.1"},
{:excoveralls, "~> 0.13", only: :test},
+ {:floki, ">= 0.0.0", only: :test},
{:argon2_elixir, "~> 2.0"},
{:phoenix_pubsub, "~> 2.0"},
{:phoenix_ecto, "~> 4.0"},
diff --git a/apps/fg_http/test/fg_http/password_resets_test.exs b/apps/fg_http/test/fg_http/password_resets_test.exs
index f911aa43e..38622a16e 100644
--- a/apps/fg_http/test/fg_http/password_resets_test.exs
+++ b/apps/fg_http/test/fg_http/password_resets_test.exs
@@ -6,8 +6,8 @@ defmodule FgHttp.PasswordResetsTest do
describe "password_resets" do
alias FgHttp.Users.PasswordReset
- @valid_attrs %{email: "test"}
- @invalid_attrs %{email: ""}
+ @valid_attrs %{email: "test@test"}
+ @invalid_attrs %{email: "invalid"}
test "get_password_reset!/1 returns the password_reset with given token" do
token = Fixtures.password_reset(%{reset_sent_at: DateTime.utc_now()}).reset_token
diff --git a/apps/fg_http/test/fg_http/util/fg_crypto_test.exs b/apps/fg_http/test/fg_http/util/fg_crypto_test.exs
new file mode 100644
index 000000000..eb97c67b2
--- /dev/null
+++ b/apps/fg_http/test/fg_http/util/fg_crypto_test.exs
@@ -0,0 +1,17 @@
+defmodule FgHttp.Util.FgCryptoTest do
+ use ExUnit.Case, async: true
+
+ alias FgHttp.Util.FgCrypto
+
+ describe "rand_string" do
+ test "it returns a string of default length" do
+ assert 16 == String.length(FgCrypto.rand_string())
+ end
+
+ test "it returns a string of proper length" do
+ for length <- [1, 32, 32_768] do
+ assert length == String.length(FgCrypto.rand_string(length))
+ end
+ end
+ end
+end
diff --git a/apps/fg_http/test/fg_http_web/controllers/device_controller_test.exs b/apps/fg_http/test/fg_http_web/controllers/device_controller_test.exs
index 0bc88925d..53f44ebec 100644
--- a/apps/fg_http/test/fg_http_web/controllers/device_controller_test.exs
+++ b/apps/fg_http/test/fg_http_web/controllers/device_controller_test.exs
@@ -1,8 +1,72 @@
-defmodule FgHttpWeb.DeviceControllerTest do
- use FgHttpWeb.ConnCase, async: true
-
+defmodule FgHttpWeb.DeviceControllerTestHelpers do
alias FgHttp.Fixtures
+ def create_device(_) do
+ device = Fixtures.device()
+ {:ok, device: device}
+ end
+end
+
+defmodule FgHttpWeb.DeviceControllerUnauthedTest do
+ use FgHttpWeb.ConnCase, async: true
+ import FgHttpWeb.DeviceControllerTestHelpers
+
+ @create_attrs %{public_key: "foobar"}
+ @update_attrs %{name: "some updated name"}
+
+ describe "index" do
+ test "redirects to new session", %{unauthed_conn: conn} do
+ test_conn = get(conn, Routes.device_path(conn, :index))
+ assert redirected_to(test_conn) == Routes.session_path(test_conn, :new)
+ end
+ end
+
+ describe "new device" do
+ test "redirects to new session", %{unauthed_conn: conn} do
+ test_conn = get(conn, Routes.device_path(conn, :new))
+ assert redirected_to(test_conn) == Routes.session_path(test_conn, :new)
+ end
+ end
+
+ describe "create device" do
+ test "redirects to new session", %{unauthed_conn: conn} do
+ test_conn = post(conn, Routes.device_path(conn, :create), device: @create_attrs)
+ assert redirected_to(test_conn) == Routes.session_path(test_conn, :new)
+ end
+ end
+
+ describe "edit device" do
+ setup [:create_device]
+
+ test "redirects to new session", %{unauthed_conn: conn, device: device} do
+ test_conn = get(conn, Routes.device_path(conn, :edit, device))
+ assert redirected_to(test_conn) == Routes.session_path(test_conn, :new)
+ end
+ end
+
+ describe "update device" do
+ setup [:create_device]
+
+ test "redirects to new session", %{unauthed_conn: conn, device: device} do
+ test_conn = put(conn, Routes.device_path(conn, :update, device), device: @update_attrs)
+ assert redirected_to(test_conn) == Routes.session_path(test_conn, :new)
+ end
+ end
+
+ describe "delete device" do
+ setup [:create_device]
+
+ test "redirects to new session", %{unauthed_conn: conn, device: device} do
+ test_conn = delete(conn, Routes.device_path(conn, :delete, device))
+ assert redirected_to(test_conn) == Routes.session_path(test_conn, :new)
+ end
+ end
+end
+
+defmodule FgHttpWeb.DeviceControllerAuthedTest do
+ use FgHttpWeb.ConnCase, async: true
+ import FgHttpWeb.DeviceControllerTestHelpers
+
@create_attrs %{public_key: "foobar"}
@update_attrs %{name: "some updated name"}
@invalid_attrs %{public_key: nil}
@@ -28,8 +92,8 @@ defmodule FgHttpWeb.DeviceControllerTest do
end
test "renders errors when data is invalid", %{authed_conn: conn} do
- conn = post(conn, Routes.device_path(conn, :create), device: @invalid_attrs)
- assert html_response(conn, 200) =~ "public_key: can't be blank"
+ test_conn = post(conn, Routes.device_path(conn, :create), device: @invalid_attrs)
+ assert html_response(test_conn, 200) =~ "public_key: can't be blank"
end
end
@@ -37,8 +101,8 @@ defmodule FgHttpWeb.DeviceControllerTest do
setup [:create_device]
test "renders form for editing chosen device", %{authed_conn: conn, device: device} do
- conn = get(conn, Routes.device_path(conn, :edit, device))
- assert html_response(conn, 200) =~ "Edit Device"
+ test_conn = get(conn, Routes.device_path(conn, :edit, device))
+ assert html_response(test_conn, 200) =~ "Edit Device"
end
end
@@ -71,9 +135,4 @@ defmodule FgHttpWeb.DeviceControllerTest do
end
end
end
-
- defp create_device(_) do
- device = Fixtures.device()
- {:ok, device: device}
- end
end
diff --git a/apps/fg_http/test/fg_http_web/controllers/password_reset_controller_test.exs b/apps/fg_http/test/fg_http_web/controllers/password_reset_controller_test.exs
index 051054a94..8e2eef9be 100644
--- a/apps/fg_http/test/fg_http_web/controllers/password_reset_controller_test.exs
+++ b/apps/fg_http/test/fg_http_web/controllers/password_reset_controller_test.exs
@@ -3,7 +3,7 @@ defmodule FgHttpWeb.PasswordResetControllerTest do
alias FgHttp.Fixtures
- @valid_create_attrs %{email: "test"}
+ @valid_create_attrs %{email: "test@test"}
@invalid_create_attrs %{email: "doesnt-exist"}
describe "new password_reset" do
diff --git a/apps/fg_http/test/fg_http_web/controllers/session_controller_test.exs b/apps/fg_http/test/fg_http_web/controllers/session_controller_test.exs
index d3fcfa6bc..23ed1eba8 100644
--- a/apps/fg_http/test/fg_http_web/controllers/session_controller_test.exs
+++ b/apps/fg_http/test/fg_http_web/controllers/session_controller_test.exs
@@ -3,8 +3,8 @@ defmodule FgHttpWeb.SessionControllerTest do
alias FgHttp.{Fixtures, Repo, Users.User}
- @valid_attrs %{email: "test", password: "test"}
- @invalid_attrs %{email: "test", password: "wrong"}
+ @valid_attrs %{email: "test@test", password: "test"}
+ @invalid_attrs %{email: "test@test", password: "wrong"}
describe "new when a user is already signed in" do
test "redirects to authenticated root", %{authed_conn: conn} do
@@ -15,11 +15,17 @@ defmodule FgHttpWeb.SessionControllerTest do
end
describe "new when a user is not signed in" do
- test "renders sign in form", %{unauthed_conn: conn} do
+ test "renders sign in form for new session path", %{unauthed_conn: conn} do
test_conn = get(conn, Routes.session_path(conn, :new))
assert html_response(test_conn, 200) =~ "Sign In"
end
+
+ test "renders sign in form for root path", %{unauthed_conn: conn} do
+ test_conn = get(conn, "/")
+
+ assert html_response(test_conn, 200) =~ "Sign In"
+ end
end
describe "create when user exists" do
diff --git a/apps/fg_http/test/fg_http_web/controllers/user_controller_test.exs b/apps/fg_http/test/fg_http_web/controllers/user_controller_test.exs
index b660e5a4f..0d8364c7a 100644
--- a/apps/fg_http/test/fg_http_web/controllers/user_controller_test.exs
+++ b/apps/fg_http/test/fg_http_web/controllers/user_controller_test.exs
@@ -4,34 +4,42 @@ defmodule FgHttpWeb.UserControllerTest do
alias FgHttp.Users.Session
@valid_create_attrs %{
- email: "fixure",
+ email: "valid@test",
password: "password",
password_confirmation: "password"
}
@invalid_create_attrs %{
- email: "fixture",
+ email: "test@test",
password: "password",
password_confirmation: "wrong_password"
}
@valid_update_attrs %{
- email: "new-email",
+ email: "test@test",
password: "new_password",
password_confirmation: "new_password"
}
+ @valid_email_attrs %{email: "test@test"}
+ @invalid_email_attrs %{email: "invalid"}
+ @empty_update_password_attrs %{
+ email: "",
+ password: "",
+ password_confirmation: "",
+ current_password: ""
+ }
@valid_update_password_attrs %{
- email: "fixture",
+ email: "test@test",
password: "new_password",
password_confirmation: "new_password",
current_password: "test"
}
@invalid_update_password_attrs %{
- email: "fixture",
+ email: "test@test",
password: "new_password",
password_confirmation: "new_password",
current_password: "wrong current password"
}
@invalid_update_attrs %{
- email: "new-email",
+ email: "test@test",
password: "new_password",
password_confirmation: "wrong_password"
}
@@ -87,9 +95,25 @@ defmodule FgHttpWeb.UserControllerTest do
assert html_response(test_conn, 200) =~ "is invalid: invalid password"
end
+
+ test "does nothing when password params are empty", %{authed_conn: conn} do
+ test_conn = put(conn, Routes.user_path(conn, :update), user: @empty_update_password_attrs)
+ end
end
describe "update" do
+ test "updates email", %{authed_conn: conn} do
+ test_conn = put(conn, Routes.user_path(conn, :update), user: @valid_email_attrs)
+
+ assert redirected_to(test_conn) == Routes.user_path(test_conn, :show)
+ end
+
+ test "renders error when email is invalid", %{authed_conn: conn} do
+ test_conn = put(conn, Routes.user_path(conn, :update), user: @invalid_email_attrs)
+
+ assert html_response(test_conn, 200) =~ "has invalid format"
+ end
+
test "updates user when params are valid", %{authed_conn: conn} do
test_conn = put(conn, Routes.user_path(conn, :update), user: @valid_update_attrs)
diff --git a/apps/fg_http/test/fg_http_web/live/new_device_live_test.exs b/apps/fg_http/test/fg_http_web/live/new_device_live_test.exs
new file mode 100644
index 000000000..2db3b6fb8
--- /dev/null
+++ b/apps/fg_http/test/fg_http_web/live/new_device_live_test.exs
@@ -0,0 +1,19 @@
+defmodule FgHttpWeb.NewDeviceLiveTest do
+ use FgHttpWeb.ConnCase, async: true
+ import Phoenix.LiveViewTest
+ @endpoint FgHttpWeb.Endpoint
+
+ test "disconnected", %{authed_conn: conn} do
+ conn = get(conn, Routes.device_path(conn, :new))
+
+ assert html_response(conn, 200) =~ "New Device"
+ end
+
+ test "mount and handle_info/2", %{authed_conn: conn} do
+ {:ok, view, html} = live_isolated(conn, FgHttpWeb.NewDeviceLive)
+ assert html =~ "When we receive a connection from your device, we'll prompt"
+ assert render(view) =~ "When we receive a connection from your device, we'll prompt"
+ send(view.pid, {:pubkey, "test pubkey"})
+ assert render(view) =~ "test pubkey"
+ end
+end
diff --git a/apps/fg_http/test/support/fixtures.ex b/apps/fg_http/test/support/fixtures.ex
index 9b564f35b..9d93ff967 100644
--- a/apps/fg_http/test/support/fixtures.ex
+++ b/apps/fg_http/test/support/fixtures.ex
@@ -5,13 +5,13 @@ defmodule FgHttp.Fixtures do
alias FgHttp.{Devices, PasswordResets, Repo, Rules, Sessions, Users, Users.User}
def user(attrs \\ %{}) do
- case Repo.get_by(User, email: "test") do
+ case Repo.get_by(User, email: "test@test") do
nil ->
- attrs =
- attrs
- |> Enum.into(%{email: "test", password: "test", password_confirmation: "test"})
+ {:ok, user} =
+ %{email: "test@test", password: "test", password_confirmation: "test"}
+ |> Map.merge(attrs)
+ |> Users.create_user()
- {:ok, user} = Users.create_user(attrs)
user
%User{} = user ->
diff --git a/docs/css/style.css b/docs/css/style.css
index 6a530b042..6f4f354ed 100644
--- a/docs/css/style.css
+++ b/docs/css/style.css
@@ -1,5 +1,80 @@
+/*
+ * fg-green: 6ece00;
+ * fg-blue: 006ece;
+ * fg-purple: 6000ce;
+ * fg-orange: ce6000;
+ * fg-yellow: cec700;
+ * fg-red: ce0006;
+ */
+a {
+ text-decoration: none;
+ color: white;
+}
+a:visited {
+ text-decoration: none;
+ color: white;
+}
+
+img.logo {
+ position: fixed;
+ left: 2ch;
+ width: 5ch;
+ height: 5ch;
+}
+
+nav {
+ margin: auto;
+ padding-top: 0;
+ height: 6ch;
+}
+
+ul.nav-links {
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ max-width: 70ch;
+ list-style-type: none;
+ margin: 0 auto;
+ padding: 0;
+ justify-content: space-between;
+}
+
+ul.nav-links li a {
+ display: block;
+ padding: 2ch 0;
+}
+
+body {
+ background-color: #006ece;
+ margin: 0;
+ padding: 0;
+}
+
main {
+ margin: 0;
+ padding: 0;
+ width: 100%;
+}
+
+main section {
+ background-color: white;
+}
+div.content {
max-width: 70ch;
padding: 2ch;
margin: auto;
}
+
+footer {
+ color: white;
+ margin: auto;
+ padding-top: 0;
+ height: 6ch;
+ height:
+}
+
+footer div {
+ margin: 0 auto;
+ padding: 2ch 0;
+ max-width: 70ch;
+}
diff --git a/docs/img/logo.svg b/docs/img/logo.svg
new file mode 100644
index 000000000..23551001d
--- /dev/null
+++ b/docs/img/logo.svg
@@ -0,0 +1,68 @@
+
+
diff --git a/docs/index.html b/docs/index.html
index e62008b67..5a8c66122 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -7,36 +7,46 @@
-
-
+
+
+
+
- FireGuard
+
+
FireGuard
-
-
Introduction
+
+
Introduction
-
-
Installation
+
+
Installation
-
-
Usage
+
+
Usage
-
-
Contributing
+
+
Contributing
+
diff --git a/mix.lock b/mix.lock
index a8a3875b9..95b1ef09d 100644
--- a/mix.lock
+++ b/mix.lock
@@ -10,7 +10,7 @@
"credo": {:hex, :credo, "1.4.0", "92339d4cbadd1e88b5ee43d427b639b68a11071b6f73854e33638e30a0ea11f5", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "1fd3b70dce216574ce3c18bdf510b57e7c4c85c2ec9cad4bff854abaf7e58658"},
"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": {:hex, :ecto, "3.4.5", "2bcd262f57b2c888b0bd7f7a28c8a48aa11dc1a2c6a858e45dd8f8426d504265", [: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", "8c6d1d4d524559e9b7a062f0498e2c206122552d63eacff0a6567ffe7a8e8691"},
"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.4", "d28bac2d420f708993baed522054870086fd45016a9d09bb2cd521b9c48d32ea", [: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", "edb49af715dd72f213b66adfd0f668a43c17ed510b5d9ac7528569b23af57fe8"},
@@ -18,8 +18,10 @@
"ex_machina": {:hex, :ex_machina, "2.4.0", "09a34c5d371bfb5f78399029194a8ff67aff340ebe8ba19040181af35315eabb", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm", "a20bc9ddc721b33ea913b93666c5d0bdca5cbad7a67540784ae277228832d72c"},
"excoveralls": {:hex, :excoveralls, "0.13.0", "4e1b7cc4e0351d8d16e9be21b0345a7e165798ee5319c7800b9138ce17e0b38e", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "fe2a56c8909564e2e6764765878d7d5e141f2af3bc8ff3b018a68ee2a218fced"},
"file_system": {:hex, :file_system, "0.2.8", "f632bd287927a1eed2b718f22af727c5aeaccc9a98d8c2bd7bff709e851dc986", [:mix], [], "hexpm", "97a3b6f8d63ef53bd0113070102db2ce05352ecf0d25390eb8d747c2bde98bca"},
+ "floki": {:hex, :floki, "0.26.0", "4df88977e2e357c6720e1b650f613444bfb48c5acfc6a0c646ab007d08ad13bf", [:mix], [{:html_entities, "~> 0.5.0", [hex: :html_entities, repo: "hexpm", optional: false]}], "hexpm", "e7b66ce7feef5518a9cd9fc7b52dd62a64028bd9cb6d6ad282a0f0fc90a4ae52"},
"gettext": {:hex, :gettext, "0.18.0", "406d6b9e0e3278162c2ae1de0a60270452c553536772167e2d701f028116f870", [:mix], [], "hexpm", "c3f850be6367ebe1a08616c2158affe4a23231c70391050bf359d5f92f66a571"},
"hackney": {:hex, :hackney, "1.16.0", "5096ac8e823e3a441477b2d187e30dd3fff1a82991a806b2003845ce72ce2d84", [:rebar3], [{:certifi, "2.5.2", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.1", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.0", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.6", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "3bf0bebbd5d3092a3543b783bf065165fa5d3ad4b899b836810e513064134e18"},
+ "html_entities": {:hex, :html_entities, "0.5.1", "1c9715058b42c35a2ab65edc5b36d0ea66dd083767bef6e3edb57870ef556549", [:mix], [], "hexpm", "30efab070904eb897ff05cd52fa61c1025d7f8ef3a9ca250bc4e6513d16c32de"},
"idna": {:hex, :idna, "6.0.1", "1d038fb2e7668ce41fbf681d2c45902e52b3cb9e9c77b55334353b222c2ee50c", [:rebar3], [{:unicode_util_compat, "0.5.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a02c8a1c4fd601215bb0b0324c8a6986749f807ce35f25449ec9e69758708122"},
"jason": {:hex, :jason, "1.2.1", "12b22825e22f468c02eb3e4b9985f3d0cb8dc40b9bd704730efa11abd2708c44", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "b659b8571deedf60f79c5a608e15414085fa141344e2716fbd6988a084b5f993"},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
@@ -29,11 +31,11 @@
"phoenix": {:hex, :phoenix, "1.5.3", "bfe0404e48ea03dfe17f141eff34e1e058a23f15f109885bbdcf62be303b49ff", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_html, "~> 2.13", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.1.2 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "8e16febeb9640d8b33895a691a56481464b82836d338bb3a23125cd7b6157c25"},
"phoenix_ecto": {:hex, :phoenix_ecto, "4.1.0", "a044d0756d0464c5a541b4a0bf4bcaf89bffcaf92468862408290682c73ae50d", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.9", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "c5e666a341ff104d0399d8f0e4ff094559b2fde13a5985d4cb5023b2c2ac558b"},
"phoenix_html": {:hex, :phoenix_html, "2.14.2", "b8a3899a72050f3f48a36430da507dd99caf0ac2d06c77529b1646964f3d563e", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "58061c8dfd25da5df1ea0ca47c972f161beb6c875cd293917045b92ffe1bf617"},
- "phoenix_live_reload": {:hex, :phoenix_live_reload, "1.2.2", "38d94c30df5e2ef11000697a4fbe2b38d0fbf79239d492ff1be87bbc33bc3a84", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "a3dec3d28ddb5476c96a7c8a38ea8437923408bc88da43e5c45d97037b396280"},
+ "phoenix_live_reload": {:hex, :phoenix_live_reload, "1.2.4", "940c0344b1d66a2e46eef02af3a70e0c5bb45a4db0bf47917add271b76cd3914", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "38f9308357dea4cc77f247e216da99fcb0224e05ada1469167520bed4cb8cccd"},
"phoenix_live_view": {:hex, :phoenix_live_view, "0.12.1", "42f591c781edbf9fab921319076b7ac635d43aa23e6748d2644563326236d7e4", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.4.16 or ~> 1.5.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14", [hex: :phoenix_html, repo: "hexpm", optional: false]}], "hexpm", "585321e98df1cd5943e370b9784e950a37ca073744eb534660c9048967c52ab6"},
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.0.0", "a1ae76717bb168cdeb10ec9d92d1480fec99e3080f011402c0a2d68d47395ffb", [:mix], [], "hexpm", "c52d948c4f261577b9c6fa804be91884b381a7f8f18450c5045975435350f771"},
- "plug": {:hex, :plug, "1.10.2", "0079345cfdf9e17da3858b83eb46bc54beb91554c587b96438f55c1477af5a86", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7898d0eb4767efb3b925fd7f9d1870d15e66e9c33b89c58d8d2ad89aa75ab3c1"},
- "plug_cowboy": {:hex, :plug_cowboy, "2.2.2", "7a09aa5d10e79b92d332a288f21cc49406b1b994cbda0fde76160e7f4cc890ea", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e82364b29311dbad3753d588febd7e5ef05062cd6697d8c231e0e007adab3727"},
+ "plug": {:hex, :plug, "1.10.3", "c9cebe917637d8db0e759039cc106adca069874e1a9034fd6e3fdd427fd3c283", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "01f9037a2a1de1d633b5a881101e6a444bcabb1d386ca1e00bb273a1f1d9d939"},
+ "plug_cowboy": {:hex, :plug_cowboy, "2.3.0", "149a50e05cb73c12aad6506a371cd75750c0b19a32f81866e1a323dda9e0e99d", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "bc595a1870cef13f9c1e03df56d96804db7f702175e4ccacdb8fc75c02a7b97e"},
"plug_crypto": {:hex, :plug_crypto, "1.1.2", "bdd187572cc26dbd95b87136290425f2b580a116d3fb1f564216918c9730d227", [:mix], [], "hexpm", "6b8b608f895b6ffcfad49c37c7883e8df98ae19c6a28113b02aa1e9c5b22d6b5"},
"postgrex": {:hex, :postgrex, "0.15.5", "aec40306a622d459b01bff890fa42f1430dac61593b122754144ad9033a2152f", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "ed90c81e1525f65a2ba2279dbcebf030d6d13328daa2f8088b9661eb9143af7f"},
"ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm", "451d8527787df716d99dc36162fca05934915db0b6141bbdac2ea8d3c7afc7d7"},