All the way baby

This commit is contained in:
Jamil Bou Kheir
2021-07-15 09:20:10 -07:00
parent 90d8474435
commit ad54cfdb0f
27 changed files with 159 additions and 136 deletions

View File

@@ -1,4 +1,6 @@
defmodule FzCommonTest do
use ExUnit.Case
doctest FzCommon
# XXX: Ensure command injection is NOT POSSIBLE
end

View File

@@ -24,6 +24,7 @@ defmodule FzHttpWeb do
import Plug.Conn
import FzHttpWeb.Gettext
import Phoenix.LiveView.Controller
import FzHttpWeb.ControllerHelpers
alias FzHttpWeb.Router.Helpers, as: Routes
end
end

View File

@@ -0,0 +1,44 @@
defmodule FzHttpWeb.ControllerHelpers do
@moduledoc """
Useful helpers for controllers
"""
import Plug.Conn,
only: [
get_session: 2,
put_resp_content_type: 2,
send_resp: 3,
halt: 1
]
import Phoenix.Controller,
only: [
redirect: 2
]
alias FzHttpWeb.Router.Helpers, as: Routes
def redirect_unauthenticated(conn, _options) do
case get_session(conn, :user_id) do
nil ->
conn
|> redirect(to: Routes.session_path(conn, :new))
_ ->
conn
end
end
def require_authenticated(conn, _options) do
case get_session(conn, :user_id) do
nil ->
conn
|> put_resp_content_type("text/plain")
|> send_resp(403, "Forbidden")
|> halt()
_ ->
conn
end
end
end

View File

@@ -0,0 +1,8 @@
defmodule FzHttpWeb.AccountController do
@moduledoc """
Handles account-related operations
"""
use FzHttpWeb, :controller
plug :redirect_unauthenticated
end

View File

@@ -4,6 +4,8 @@ defmodule FzHttpWeb.DeviceController do
"""
use FzHttpWeb, :controller
plug :redirect_unauthenticated
def index(conn, _params) do
render(conn, "index.html", nav_active: "Devices", page_heading: "Devices")
end

View File

@@ -4,6 +4,8 @@ defmodule FzHttpWeb.RuleController do
"""
use FzHttpWeb, :controller
plug :redirect_unauthenticated
def index(conn, _params) do
render(conn, "index.html", page_heading: "Rules")
end

View File

@@ -3,13 +3,40 @@ defmodule FzHttpWeb.SessionController do
Implements the CRUD for a Session
"""
alias FzHttp.Users
alias FzHttp.{Sessions, Users}
use FzHttpWeb, :controller
plug :put_root_layout, "auth.html"
def new(conn, _params) do
render(conn, "new.html")
changeset = Sessions.new_session()
render(conn, "new.html", changeset: changeset)
end
# POST /sessions
def create(conn, %{"session" => %{"email" => email, "password" => password}}) do
case Sessions.get_session(email: email) do
nil ->
conn
|> put_flash(:error, "Email not found.")
|> assign(:changeset, Sessions.new_session())
|> render("new.html")
record ->
case Sessions.create_session(record, %{email: email, password: password}) do
{:ok, session} ->
conn
|> clear_session()
|> put_session(:user_id, session.id)
|> redirect(to: Routes.device_path(conn, :index))
{:error, _changeset} ->
conn
|> put_flash(:error, "Error signing in. Ensure email and password are correct.")
|> assign(:changeset, Sessions.new_session())
|> render("new.html")
end
end
end
# GET /sign_in/:token
@@ -19,13 +46,12 @@ defmodule FzHttpWeb.SessionController do
conn
|> clear_session()
|> put_session(:user_id, user.id)
|> put_flash(:info, "Signed in successfully.")
|> redirect(to: Routes.root_index_path(conn, :index))
|> redirect(to: Routes.device_path(conn, :index))
{:error, error_msg} ->
conn
|> put_flash(:error, error_msg)
|> redirect(to: Routes.session_new_path(conn, :new))
|> redirect(to: Routes.session_path(conn, :new))
end
end

View File

@@ -6,7 +6,7 @@ defmodule FzHttpWeb.UserController do
alias FzHttp.Users
use FzHttpWeb, :controller
plug :redirect_unauthenticated
plug :require_authenticated
def delete(conn, _params) do
user_id = get_session(conn, :user_id)
@@ -18,27 +18,13 @@ defmodule FzHttpWeb.UserController do
conn
|> clear_session()
|> put_flash(:info, "Account deleted successfully.")
|> redirect(to: Routes.root_index_path(conn, :index))
|> redirect(to: Routes.session_path(conn, :new))
# delete_user is unlikely to fail, if so write a test for it and uncomment this
# {:error, msg} ->
# conn
# |> clear_session()
# |> put_flash(:error, "Error deleting account: #{msg}")
# |> redirect(to: Routes.root_index_path(conn, :index))
end
end
def redirect_unauthenticated(conn, _options) do
case get_session(conn, :user_id) do
nil ->
conn
|> put_resp_content_type("text/plain")
|> send_resp(403, "Forbidden")
|> halt()
_ ->
{:error, msg} ->
conn
|> clear_session()
|> put_flash(:error, "Error deleting account: #{msg}")
|> redirect(to: Routes.session_path(conn, :new))
end
end
end

View File

@@ -8,7 +8,9 @@ defmodule FzHttpWeb.AccountLive.Show do
@impl true
def mount(params, session, socket) do
{:ok, assign_defaults(params, session, socket, &load_data/2)}
{:ok,
socket
|> assign_defaults(params, session, &load_data/2)}
end
@impl true

View File

@@ -7,7 +7,10 @@ defmodule FzHttpWeb.DeviceLive.Index do
alias FzHttp.Devices
def mount(params, session, socket) do
{:ok, assign_defaults(params, session, socket, &load_data/2)}
{:ok,
socket
|> assign_defaults(params, session, &load_data/2)
|> assign(:page_heading, "Devices")}
end
def handle_event("create_device", _params, socket) do

View File

@@ -8,7 +8,9 @@ defmodule FzHttpWeb.DeviceLive.Show do
@impl true
def mount(params, session, socket) do
{:ok, assign_defaults(params, session, socket, &load_data/2)}
{:ok,
socket
|> assign_defaults(params, session, &load_data/2)}
end
@impl true

View File

@@ -5,6 +5,8 @@ defmodule FzHttpWeb.RuleLive.Index do
use FzHttpWeb, :live_view
def mount(params, session, socket) do
{:ok, assign_defaults(params, session, socket)}
{:ok,
socket
|> assign_defaults(params, session)}
end
end

View File

@@ -34,15 +34,6 @@ defmodule FzHttpWeb.SessionLive.New do
end
end
# Guess email if signups are disabled and only one user exists
def email_field_opts(opts \\ []) do
if Users.single_user?() and signups_disabled?() do
opts ++ [value: Users.admin_email()]
else
opts
end
end
defp redirect_to_sign_in(socket, session) do
case create_sign_in_token(session) do
{:ok, token} ->
@@ -68,10 +59,6 @@ defmodule FzHttpWeb.SessionLive.New do
end
end
defp signups_disabled? do
Application.fetch_env!(:fz_http, :disable_signup)
end
defp sign_in_params do
FzMap.stringify_keys(Users.sign_in_keys())
end

View File

@@ -5,11 +5,6 @@ defmodule FzHttpWeb.Router do
use FzHttpWeb, :router
# View emails locally in development
if Mix.env() == :dev do
forward "/sent_emails", Bamboo.SentEmailViewerPlug
end
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
@@ -27,23 +22,18 @@ defmodule FzHttpWeb.Router do
pipe_through :browser
get "/", DeviceController, :index
get "/devices", DeviceController, :index
get "/rules", RuleController, :index
get "/session/new", SessionController, :new
resources "/session", SessionController, only: [:new, :create, :delete]
# live "/sign_in", SessionLive.New, :new
# live "/sign_up", UserLive.New, :new
# live "/account", AccountLive.Show, :show
# live "/account/edit", AccountLive.Show, :edit
live "/account", AccountLive.Show, :show
live "/account/edit", AccountLive.Show, :edit
# live "/rules", RuleLive.Index, :index
live "/rules", RuleLive.Index, :index
# live "/devices", DeviceLive.Index, :index
# live "/devices/:id", DeviceLive.Show, :show
# live "/devices/:id/edit", DeviceLive.Show, :edit
live "/devices", DeviceLive.Index, :index
live "/devices/:id", DeviceLive.Show, :show
live "/devices/:id/edit", DeviceLive.Show, :edit
get "/sign_in/:token", SessionController, :create
post "/sign_out", SessionController, :delete
delete "/user", UserController, :delete
end
end

View File

@@ -1 +0,0 @@
<h1>Devices</h1>

View File

@@ -18,6 +18,7 @@
<% end %>
</div>
<% end %>
<!-- foobar -->
<div class="container">
<%= @inner_content %>
</div>

View File

@@ -1,47 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<%= csrf_meta_tag() %>
<%= live_title_tag assigns[:page_title] || "FireZone" %>
<link phx-track-static rel="stylesheet" href="<%= Routes.static_path(@conn, "/css/app.css") %>"/>
<script defer phx-track-static type="text/javascript" src="<%= Routes.static_path(@conn, "/js/app.js") %>"></script>
</head>
<body>
<nav class="navbar" role="navigation" aria-label="main navigation">
<div class="container">
<div class="navbar-brand">
<h4 class="title is-4 navbar-item">
FireZone
</h4>
</div>
<div class="navbar-menu">
<%= if assigns[:current_user] do %>
<div class="navbar-start">
<%= live_redirect("Devices", to: Routes.device_index_path(@conn, :index), class: "navbar-item") %>
</div>
<% end %>
</div>
<div class="navbar-end">
<%= if assigns[:current_user] do %>
<div class="navbar-item">
<%= live_redirect("Your Account", to: Routes.account_show_path(@conn, :show)) %>
</div>
<div class="navbar-item">
<%= link("Sign out", to: Routes.session_path(@conn, :delete), method: :post) %>
</div>
<% else %>
<div class="navbar-item">
<%= live_redirect("Sign in", to: Routes.session_new_path(@conn, :new)) %>
</div>
<% end %>
</div>
</div>
</nav>
<section class="section">
<%= @inner_content %>
</section>
</body>
</html>

View File

@@ -62,10 +62,10 @@
<span>Messages</span>
</a>
<hr class="navbar-divider">
<a class="navbar-item">
<%= link(to: Routes.session_path(@conn, :delete, "noop"), method: :delete, class: "navbar-item") do %>
<span class="icon"><i class="mdi mdi-logout"></i></span>
<span>Log Out</span>
</a>
<% end %>
</div>
</div>
<div class="navbar-item has-dropdown has-dropdown-with-icons has-divider has-user-avatar is-hoverable">
@@ -130,13 +130,13 @@
<p class="menu-label">Configuration</p>
<ul class="menu-list">
<li>
<%= link(to: Routes.device_path(@conn, :index), class: nav_class(@conn.request_path, :devices)) do %>
<%= link(to: Routes.device_index_path(@conn, :index), class: nav_class(@conn.request_path, :devices)) do %>
<span class="icon has-update-mark"><i class="mdi mdi-table"></i></span>
<span class="menu-item-label">Devices</span>
<% end %>
</li>
<li>
<%= link(to: Routes.rule_path(@conn, :index), class: nav_class(@conn.request_path, :rules)) do %>
<%= link(to: Routes.rule_index_path(@conn, :index), class: nav_class(@conn.request_path, :rules)) do %>
<span class="icon"><i class="mdi mdi-square-edit-outline"></i></span>
<span class="menu-item-label">Rules</span>
<% end %>
@@ -144,12 +144,6 @@
</ul>
<p class="menu-label">Settings</p>
<ul class="menu-list">
<li>
<a href="https://admin-one-html.justboil.me/" target="_blank" class="has-icon">
<span class="icon"><i class="mdi mdi-credit-card-outline"></i></span>
<span class="menu-item-label">Admin</span>
</a>
</li>
<li>
<a href="https://justboil.me/bulma-admin-template/one-html" class="has-icon">
<span class="icon"><i class="mdi mdi-help-circle"></i></span>
@@ -197,6 +191,11 @@
</div>
</div>
</section>
<section class="section is-main-section">
<%= @inner_content %>
</section>
<footer class="footer">
<div class="container-fluid">
<div class="level">
@@ -213,7 +212,7 @@
<div class="level-right">
<div class="level-item">
<div class="logo">
<a href="https://justboil.me"><img src="images/logo.svg" alt="firez.one"></a>
<a href="https://firez.one"><img src="images/logo.svg" alt="firez.one"></a>
</div>
</div>
</div>

View File

@@ -2,7 +2,7 @@
<h3 class="title">Sign In</h3>
<hr>
<%= form_for @changeset, "#", [id: "sign-in", phx_submit: :sign_in], fn f -> %>
<%= form_for @changeset, Routes.session_path(@conn, :create), fn f -> %>
<%= if assigns[:changeset] && @changeset.action do %>
<div>
<p>Oops, something went wrong! Please check the errors below.</p>

View File

@@ -1,3 +0,0 @@
defmodule FzHttpWeb.EmailView do
use FzHttpWeb, :view
end

View File

@@ -16,7 +16,6 @@ defmodule FzHttpWeb.LayoutView do
def nav_class("/", :devices), do: "is-active has-icon"
def nav_class("/devices", :devices), do: "is-active has-icon"
def nav_class("/rules", :rules), do: "is-active has-icon"
def nav_class("/admin", :admin), do: "is-active has-icon"
def nav_class("/account", :account), do: "is-active has-icon"
def nav_class(_, _), do: "has-icon"
end

View File

@@ -10,7 +10,7 @@ defmodule FzHttpWeb.LiveHelpers do
@doc """
Load user into socket assigns and call the callback function if provided.
"""
def assign_defaults(params, %{"user_id" => user_id}, socket, callback) do
def assign_defaults(socket, params, %{"user_id" => user_id}, callback) do
socket = assign_new(socket, :current_user, fn -> Users.get_user(user_id) end)
if socket.assigns.current_user do
@@ -20,22 +20,22 @@ defmodule FzHttpWeb.LiveHelpers do
end
end
def assign_defaults(_params, _session, socket, _decorator) do
def assign_defaults(socket, _params, _session, _decorator) do
not_authorized(socket)
end
def assign_defaults(_params, %{"user_id" => user_id}, socket) do
def assign_defaults(socket, _params, %{"user_id" => user_id}) do
assign_new(socket, :current_user, fn -> Users.get_user!(user_id) end)
end
def assign_defaults(_params, _session, socket) do
def assign_defaults(socket, _params, _session) do
not_authorized(socket)
end
def not_authorized(socket) do
socket
|> put_flash(:error, "Not authorized.")
|> redirect(to: Routes.session_new_path(socket, :new))
|> redirect(to: Routes.session_path(socket, :new))
end
def live_modal(component, opts) do

View File

@@ -0,0 +1,14 @@
defmodule FzHttpWeb.SessionView do
use FzHttpWeb, :view
alias FzHttp.Users
# Guess email if signups are disabled and only one user exists
def email_field_opts(opts \\ []) do
if Users.single_user?() do
opts ++ [value: Users.admin_email()]
else
opts
end
end
end

View File

@@ -37,6 +37,10 @@ defmodule FzWall.CLI.Live do
exec!("iptables -A firezone -s #{s} -d #{d} -j DROP")
end
def add_rule({4, d, :deny}) do
exec!("iptables -A firezone -d #{d} -j DROP")
end
def add_rule({4, s, d, :allow}) do
exec!("iptables -A firezone -s #{s} -d #{d} -j ACCEPT")
end

View File

@@ -9,8 +9,6 @@ config :fz_http, FzHttp.Repo,
show_sensitive_data_on_connection_error: true,
pool_size: 10
config :fz_http, FzHttp.Mailer, adapter: Bamboo.LocalAdapter
# For development, we disable any cache and enable
# debugging and code reloading.
#

View File

@@ -27,8 +27,6 @@ end
db_url = System.get_env("DATABASE_URL")
config :fz_http, FzHttp.Repo, DBConfig.config(db_url)
config :fz_http, FzHttp.Mailer, adapter: Bamboo.TestAdapter
# We don't run a server during test. If one is required,
# you can enable the server option below.
config :fz_http, FzHttpWeb.Endpoint,

View File

@@ -3,10 +3,14 @@ set -e
# Required due to a buildx bug.
# See https://github.com/docker/buildx/issues/495#issuecomment-761562905
docker buildx rm multiarch || true
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
docker buildx create --name multiarch --driver docker-container --use
docker buildx inspect --bootstrap
if [ `uname -m` = "amd64" ]; then
docker buildx rm multiarch || true
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
docker buildx create --name multiarch --driver docker-container --use
docker buildx inspect --bootstrap
elif [ `uname -m` = "arm64" ]; then
docker buildx create --use
fi
.ci/build_amazonlinux_2.base.sh
.ci/build_centos_7.base.sh
.ci/build_centos_8.base.sh