mirror of
https://github.com/outbackdingo/firezone.git
synced 2026-01-27 18:18:55 +00:00
Fix device delete
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
# source .env
|
||||
# set +a
|
||||
|
||||
DATABASE_URL="ecto://fireguard:postgres@localhost/fireguard_dev"
|
||||
DATABASE_URL="ecto://firezone:postgres@localhost/firezone_dev"
|
||||
|
||||
# Generate with mix phx.gen.secret
|
||||
SECRET_KEY_BASE=
|
||||
@@ -14,8 +14,7 @@ SECRET_KEY_BASE=
|
||||
# Generate with mix phx.gen.secret 32
|
||||
LIVE_VIEW_SIGNING_SALT=
|
||||
|
||||
# Generate with wg genkey
|
||||
WIREGUARD_PRIVATE_KEY=
|
||||
WIREGUARD_PUBLIC_KEY=
|
||||
WIREGUARD_PORT=51820
|
||||
WIREGUARD_INTERFACE_NAME=wg-firezone
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ defmodule FzCommon.CLI do
|
||||
"""
|
||||
|
||||
def bash(cmd) do
|
||||
System.cmd("bash", ["-c", cmd])
|
||||
System.cmd("bash", ["-c", cmd], stderr_to_stdout: true)
|
||||
end
|
||||
|
||||
def exec!(cmd) do
|
||||
@@ -12,9 +12,9 @@ defmodule FzCommon.CLI do
|
||||
{result, 0} ->
|
||||
result
|
||||
|
||||
{error, _} ->
|
||||
{error, exit_code} ->
|
||||
raise """
|
||||
Error executing command #{cmd} with error #{error}.
|
||||
Error executing command #{cmd}. Exited with code #{exit_code} and error #{error}.
|
||||
FireZone cannot recover from this error.
|
||||
"""
|
||||
end
|
||||
|
||||
@@ -47,8 +47,7 @@ defmodule FzHttp.Devices do
|
||||
for device <- Repo.all(Device) do
|
||||
%{
|
||||
public_key: device.public_key,
|
||||
allowed_ips: device.allowed_ips,
|
||||
preshared_key: device.preshared_key
|
||||
allowed_ips: device.allowed_ips
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -12,7 +12,6 @@ defmodule FzHttp.Devices.Device do
|
||||
field :name, :string
|
||||
field :public_key, :string
|
||||
field :allowed_ips, :string
|
||||
field :preshared_key, FzHttp.Encrypted.Binary
|
||||
field :private_key, FzHttp.Encrypted.Binary
|
||||
field :server_public_key, :string
|
||||
field :remote_ip, EctoNetwork.INET
|
||||
@@ -36,7 +35,6 @@ defmodule FzHttp.Devices.Device do
|
||||
:interface_address6,
|
||||
:server_public_key,
|
||||
:private_key,
|
||||
:preshared_key,
|
||||
:user_id,
|
||||
:name,
|
||||
:public_key
|
||||
@@ -46,12 +44,10 @@ defmodule FzHttp.Devices.Device do
|
||||
:name,
|
||||
:public_key,
|
||||
:server_public_key,
|
||||
:private_key,
|
||||
:preshared_key
|
||||
:private_key
|
||||
])
|
||||
|> unique_constraint(:public_key)
|
||||
|> unique_constraint(:private_key)
|
||||
|> unique_constraint(:preshared_key)
|
||||
|> unique_constraint([:user_id, :name])
|
||||
end
|
||||
end
|
||||
|
||||
@@ -9,8 +9,8 @@ defmodule FzHttpWeb.Events do
|
||||
GenServer.call(vpn_pid(), :create_device)
|
||||
end
|
||||
|
||||
def device_created(pubkey, psk, ip) do
|
||||
GenServer.cast(vpn_pid(), {:device_created, pubkey, psk, ip})
|
||||
def device_created(pubkey, ip) do
|
||||
GenServer.cast(vpn_pid(), {:device_created, pubkey, ip})
|
||||
end
|
||||
|
||||
def delete_device(device_pubkey) do
|
||||
|
||||
@@ -7,27 +7,33 @@
|
||||
user: @current_user,
|
||||
action: @live_action) %>
|
||||
<% end %>
|
||||
<div class="columns">
|
||||
<div class="column is-6">
|
||||
<div class="content">
|
||||
<dl>
|
||||
<dt>
|
||||
<strong>Email</strong>
|
||||
</dt>
|
||||
<dd><%= @current_user.email %></dd>
|
||||
|
||||
<dt><strong>Last signed in at</strong></dt>
|
||||
<dd><%= @current_user.last_signed_in_at %></dd>
|
||||
</dl>
|
||||
<%= render FzHttpWeb.SharedView, "heading.html", page_title: @page_title %>
|
||||
|
||||
<div class="level">
|
||||
<%= live_patch("Change email or password", to: Routes.account_show_path(@socket, :edit)) %>
|
||||
<section class="section is-main-section">
|
||||
<%= render FzHttpWeb.SharedView, "flash.html", assigns %>
|
||||
<div class="columns">
|
||||
<div class="column is-6">
|
||||
<div class="content">
|
||||
<dl>
|
||||
<dt>
|
||||
<strong>Email</strong>
|
||||
</dt>
|
||||
<dd><%= @current_user.email %></dd>
|
||||
|
||||
<%# This is purposefully a synchronous form in order to easily clear the session %>
|
||||
<%= form_for @changeset, Routes.user_path(@socket, :delete), [id: "delete-account", method: :delete], fn _f -> %>
|
||||
<%= submit "Delete your account", class: "button is-danger", data: [confirm: "Are you sure?"] %>
|
||||
<% end %>
|
||||
<dt><strong>Last signed in at</strong></dt>
|
||||
<dd><%= @current_user.last_signed_in_at %></dd>
|
||||
</dl>
|
||||
|
||||
<div class="level">
|
||||
<%= live_patch("Change email or password", to: Routes.account_show_path(@socket, :edit)) %>
|
||||
|
||||
<%# This is purposefully a synchronous form in order to easily clear the session %>
|
||||
<%= form_for @changeset, Routes.user_path(@socket, :delete), [id: "delete-account", method: :delete], fn _f -> %>
|
||||
<%= submit "Delete your account", class: "button is-danger", data: [confirm: "Are you sure?"] %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -1,30 +1,36 @@
|
||||
<div class="content">
|
||||
<hr>
|
||||
<%= render FzHttpWeb.SharedView, "heading.html", page_title: @page_title %>
|
||||
|
||||
<table class="table is-striped is-fullwidth">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Public key</th>
|
||||
<th>Remote IP</th>
|
||||
<th>Last seen at</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<%= for device <- @devices do %>
|
||||
<tr>
|
||||
<td>
|
||||
<%= link(device.name, to: Routes.device_show_path(@socket, :show, device)) %>
|
||||
</td>
|
||||
<td class="code"><%= device.public_key %></td>
|
||||
<td class="code"><%= device.remote_ip || "Never connected" %></td>
|
||||
<td><%= device.last_seen_at %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<section class="section is-main-section">
|
||||
<%= render FzHttpWeb.SharedView, "flash.html", assigns %>
|
||||
|
||||
<button class="button is-primary" phx-click="create_device">
|
||||
Add Device
|
||||
</button>
|
||||
<div class="content">
|
||||
<hr>
|
||||
|
||||
<table class="table is-striped is-fullwidth">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Public key</th>
|
||||
<th>Remote IP</th>
|
||||
<th>Last seen at</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<%= for device <- @devices do %>
|
||||
<tr>
|
||||
<td>
|
||||
<%= live_redirect(device.name, to: Routes.device_show_path(@socket, :show, device)) %>
|
||||
</td>
|
||||
<td class="code"><%= device.public_key %></td>
|
||||
<td class="code"><%= device.remote_ip || "Never connected" %></td>
|
||||
<td><%= device.last_seen_at %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<button class="button is-primary" phx-click="create_device">
|
||||
Add Device
|
||||
</button>
|
||||
</section>
|
||||
|
||||
@@ -15,13 +15,12 @@ defmodule FzHttpWeb.DeviceLive.Index do
|
||||
|
||||
def handle_event("create_device", _params, socket) do
|
||||
# XXX: Remove device from WireGuard if create isn't successful
|
||||
{:ok, privkey, pubkey, server_pubkey, psk} = @events_module.create_device()
|
||||
{:ok, privkey, pubkey, server_pubkey} = @events_module.create_device()
|
||||
|
||||
device_attrs = %{
|
||||
private_key: privkey,
|
||||
public_key: pubkey,
|
||||
server_public_key: server_pubkey,
|
||||
preshared_key: psk
|
||||
server_public_key: server_pubkey
|
||||
}
|
||||
|
||||
attributes =
|
||||
@@ -37,7 +36,6 @@ defmodule FzHttpWeb.DeviceLive.Index do
|
||||
{:ok, device} ->
|
||||
@events_module.device_created(
|
||||
device.public_key,
|
||||
device.preshared_key,
|
||||
"10.3.2.#{device.octet_sequence}"
|
||||
)
|
||||
|
||||
|
||||
@@ -8,78 +8,77 @@
|
||||
action: @live_action) %>
|
||||
<% end %>
|
||||
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<div class="level">
|
||||
<div class="level-left">
|
||||
<h4 class="is-4 title">Device Details</h4>
|
||||
<%= render FzHttpWeb.SharedView, "heading.html", page_title: @page_title %>
|
||||
|
||||
<section class="section is-main-section">
|
||||
<%= render FzHttpWeb.SharedView, "flash.html", assigns %>
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<div class="level">
|
||||
<div class="level-left">
|
||||
<h4 class="is-4 title">Device Details</h4>
|
||||
</div>
|
||||
<div class="level-right">
|
||||
<%= live_patch("Edit", to: Routes.device_show_path(@socket, :edit, @device)) %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="level-right">
|
||||
<%= live_patch("Edit", to: Routes.device_show_path(@socket, :edit, @device)) %>
|
||||
<hr>
|
||||
<div class="content">
|
||||
<dl>
|
||||
<dt>
|
||||
<strong>Name:</strong>
|
||||
</dt>
|
||||
<dd><%= @device.name %></dd>
|
||||
|
||||
<dt>
|
||||
<strong>Interface IP:</strong>
|
||||
</dt>
|
||||
<dd>10.3.2.<%= @device.octet_sequence %></dd>
|
||||
|
||||
<dt>
|
||||
<strong>Public key:</strong>
|
||||
</dt>
|
||||
<dd class="code"><%= @device.public_key %></dd>
|
||||
|
||||
<dt>
|
||||
<strong>Private key:</strong>
|
||||
</dt>
|
||||
<dd class="code"><%= @device.private_key %></dd>
|
||||
|
||||
<dt>
|
||||
<strong>Server Public key:</strong>
|
||||
</dt>
|
||||
<dd class="code"><%= @device.server_public_key %></dd>
|
||||
|
||||
<dt>
|
||||
<strong>Remote IP:</strong>
|
||||
</dt>
|
||||
<dd class="code"><%= @device.remote_ip %></dd>
|
||||
|
||||
<dt>
|
||||
<strong>Last seen at:</strong>
|
||||
</dt>
|
||||
<dd><%= @device.last_seen_at %></dd>
|
||||
</dl>
|
||||
</div>
|
||||
<div class="level">
|
||||
<%= live_redirect("Back to Devices", to: Routes.device_index_path(@socket, :index), class: "button") %>
|
||||
<button class="button is-danger"
|
||||
phx-click="delete_device"
|
||||
phx-value-device_id={@device.id}
|
||||
data-confirm="Are you sure? This will remove all data associated with this device.">
|
||||
Delete device
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="content">
|
||||
<dl>
|
||||
<dt>
|
||||
<strong>Name:</strong>
|
||||
</dt>
|
||||
<dd><%= @device.name %></dd>
|
||||
|
||||
<dt>
|
||||
<strong>Interface IP:</strong>
|
||||
</dt>
|
||||
<dd>10.3.2.<%= @device.octet_sequence %></dd>
|
||||
|
||||
<dt>
|
||||
<strong>Public key:</strong>
|
||||
</dt>
|
||||
<dd class="code"><%= @device.public_key %></dd>
|
||||
|
||||
<dt>
|
||||
<strong>Private key:</strong>
|
||||
</dt>
|
||||
<dd class="code"><%= @device.private_key %></dd>
|
||||
|
||||
<dt>
|
||||
<strong>Preshared key:</strong>
|
||||
</dt>
|
||||
<dd class="code"><%= @device.preshared_key %></dd>
|
||||
|
||||
<dt>
|
||||
<strong>Server Public key:</strong>
|
||||
</dt>
|
||||
<dd class="code"><%= @device.server_public_key %></dd>
|
||||
|
||||
<dt>
|
||||
<strong>Remote IP:</strong>
|
||||
</dt>
|
||||
<dd class="code"><%= @device.remote_ip %></dd>
|
||||
|
||||
<dt>
|
||||
<strong>Last seen at:</strong>
|
||||
</dt>
|
||||
<dd><%= @device.last_seen_at %></dd>
|
||||
</dl>
|
||||
</div>
|
||||
<div class="level">
|
||||
<%= link("Back to Devices", to: Routes.device_index_path(@socket, :index), class: "button") %>
|
||||
<button class="button is-danger"
|
||||
phx-click="delete_device"
|
||||
phx-value-device_id={@device.id}
|
||||
data-confirm="Are you sure? This will remove all data associated with this device.">
|
||||
Delete device
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column">
|
||||
<h4 class="is-4 title">Config</h4>
|
||||
<hr>
|
||||
<div class="content">
|
||||
<h6 class="is-6 title">
|
||||
Add the following to your WireGuard™ configuration file:
|
||||
</h6>
|
||||
<pre><code id="wg-conf">
|
||||
<div class="column">
|
||||
<h4 class="is-4 title">Config</h4>
|
||||
<hr>
|
||||
<div class="content">
|
||||
<h6 class="is-6 title">
|
||||
Add the following to your WireGuard™ configuration file:
|
||||
</h6>
|
||||
<pre><code id="wg-conf">
|
||||
[Interface]
|
||||
PrivateKey = <%= @device.private_key %>
|
||||
Address = 10.3.2.<%= @device.octet_sequence %>
|
||||
@@ -89,12 +88,13 @@ DNS = 1.1.1.1, 1.0.0.1
|
||||
PublicKey = <%= @device.server_public_key %>
|
||||
AllowedIPs = 0.0.0.0/0, ::/0
|
||||
Endpoint = <%= @wireguard_endpoint_ip %>:<%= @wireguard_port %></code></pre>
|
||||
<h6 class="is-6 title">
|
||||
Or scan the QR code with your mobile phone:
|
||||
</h6>
|
||||
<div class="has-text-centered">
|
||||
<canvas id="qr-canvas" phx-hook="QrCode"></canvas>
|
||||
<h6 class="is-6 title">
|
||||
Or scan the QR code with your mobile phone:
|
||||
</h6>
|
||||
<div class="has-text-centered">
|
||||
<canvas id="qr-canvas" phx-hook="QrCode"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -1,18 +1,23 @@
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<%= live_component(
|
||||
@socket,
|
||||
FzHttpWeb.RuleLive.RuleListComponent,
|
||||
title: "Allowlist",
|
||||
id: :allowlist,
|
||||
current_user: @current_user) %>
|
||||
<%= render FzHttpWeb.SharedView, "heading.html", page_title: @page_title %>
|
||||
|
||||
<section class="section is-main-section">
|
||||
<%= render FzHttpWeb.SharedView, "flash.html", assigns %>
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<%= live_component(
|
||||
@socket,
|
||||
FzHttpWeb.RuleLive.RuleListComponent,
|
||||
title: "Allowlist",
|
||||
id: :allowlist,
|
||||
current_user: @current_user) %>
|
||||
</div>
|
||||
<div class="column">
|
||||
<%= live_component(
|
||||
@socket,
|
||||
FzHttpWeb.RuleLive.RuleListComponent,
|
||||
title: "Denylist",
|
||||
id: :denylist,
|
||||
current_user: @current_user) %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column">
|
||||
<%= live_component(
|
||||
@socket,
|
||||
FzHttpWeb.RuleLive.RuleListComponent,
|
||||
title: "Denylist",
|
||||
id: :denylist,
|
||||
current_user: @current_user) %>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -8,14 +8,14 @@ defmodule FzHttpWeb.MockEvents do
|
||||
"""
|
||||
|
||||
def create_device do
|
||||
{:ok, "privkey", "pubkey", "server_pubkey", "preshared_key"}
|
||||
{:ok, "privkey", "pubkey", "server_pubkey"}
|
||||
end
|
||||
|
||||
def delete_device(pubkey) do
|
||||
{:ok, pubkey}
|
||||
end
|
||||
|
||||
def device_created(_pubkey, _psk, _ip) do
|
||||
def device_created(_pubkey, _ip) do
|
||||
:ok
|
||||
end
|
||||
|
||||
|
||||
@@ -1,27 +1,3 @@
|
||||
<%= if !is_nil(live_flash(@flash, :info)) or !is_nil(live_flash(@flash, :error)) do %>
|
||||
<div class="container flash-squeeze">
|
||||
<%= if live_flash(@flash, :info) do %>
|
||||
<div class="notification is-info">
|
||||
<button title="Dismiss notification"
|
||||
class="delete"
|
||||
phx-click="lv:clear-flash"
|
||||
phx-value-key="info"
|
||||
></button>
|
||||
<div class="flash-info"><%= live_flash(@flash, :info) %></div>
|
||||
</div>
|
||||
<% end %>
|
||||
<%= if live_flash(@flash, :error) do %>
|
||||
<div class="notification is-danger">
|
||||
<button title="Dismiss notification"
|
||||
class="delete"
|
||||
phx-click="lv:clear-flash"
|
||||
phx-value-key="error"
|
||||
></button>
|
||||
<div class="flash-error"><%= live_flash(@flash, :error) %></div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
<div>
|
||||
<%= @inner_content %>
|
||||
</div>
|
||||
|
||||
@@ -94,26 +94,8 @@
|
||||
</ul>
|
||||
</div>
|
||||
</aside>
|
||||
<section class="hero is-hero-bar">
|
||||
<div class="hero-body">
|
||||
<div class="level">
|
||||
<div class="level-left">
|
||||
<div class="level-item">
|
||||
<h1 class="title">
|
||||
<%= @page_title %>
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="level-right" style="display: none;">
|
||||
<div class="level-item"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section is-main-section">
|
||||
<%= @inner_content %>
|
||||
</section>
|
||||
<%= @inner_content %>
|
||||
|
||||
<footer class="footer">
|
||||
<div class="container-fluid">
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
<%= if !is_nil(live_flash(@flash, :info)) or !is_nil(live_flash(@flash, :error)) do %>
|
||||
<div class="container flash-squeeze">
|
||||
<%= if live_flash(@flash, :info) do %>
|
||||
<div class="notification is-info">
|
||||
<button title="Dismiss notification"
|
||||
class="delete"
|
||||
phx-click="lv:clear-flash"
|
||||
phx-value-key="info"
|
||||
></button>
|
||||
<div class="flash-info"><%= live_flash(@flash, :info) %></div>
|
||||
</div>
|
||||
<% end %>
|
||||
<%= if live_flash(@flash, :error) do %>
|
||||
<div class="notification is-danger">
|
||||
<button title="Dismiss notification"
|
||||
class="delete"
|
||||
phx-click="lv:clear-flash"
|
||||
phx-value-key="error"
|
||||
></button>
|
||||
<div class="flash-error"><%= live_flash(@flash, :error) %></div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
@@ -0,0 +1,16 @@
|
||||
<section class="hero is-hero-bar">
|
||||
<div class="hero-body">
|
||||
<div class="level">
|
||||
<div class="level-left">
|
||||
<div class="level-item">
|
||||
<h1 class="title">
|
||||
<%= @page_title %>
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="level-right" style="display: none;">
|
||||
<div class="level-item"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
3
apps/fz_http/lib/fz_http_web/views/shared_view.ex
Normal file
3
apps/fz_http/lib/fz_http_web/views/shared_view.ex
Normal file
@@ -0,0 +1,3 @@
|
||||
defmodule FzHttpWeb.SharedView do
|
||||
use FzHttpWeb, :view
|
||||
end
|
||||
@@ -6,7 +6,6 @@ defmodule FzHttp.Repo.Migrations.CreateDevices do
|
||||
add :name, :string, null: false
|
||||
add :public_key, :string, null: false
|
||||
add :allowed_ips, :string
|
||||
add :preshared_key, :bytea, null: false
|
||||
add :private_key, :bytea, null: false
|
||||
add :server_public_key, :string, null: false
|
||||
add :remote_ip, :inet
|
||||
@@ -23,7 +22,6 @@ defmodule FzHttp.Repo.Migrations.CreateDevices do
|
||||
create index(:devices, [:user_id])
|
||||
create unique_index(:devices, [:public_key])
|
||||
create unique_index(:devices, [:private_key])
|
||||
create unique_index(:devices, [:preshared_key])
|
||||
create unique_index(:devices, [:user_id, :name])
|
||||
create unique_index(:devices, [:octet_sequence])
|
||||
end
|
||||
|
||||
@@ -26,7 +26,6 @@ alias FzHttp.{Devices, Rules, Users}
|
||||
public_key: "3Fo+SNnDJ6hi8qzPt3nWLwgjCVwvpjHL35qJeatKwEc=",
|
||||
server_public_key: "QFvMfHTjlJN9cfUiK1w4XmxOomH6KRTCMrVC6z3TWFM=",
|
||||
private_key: "2JSZtpSHM+69Hm7L3BSGIymbq0byw39iWLevKESd1EM=",
|
||||
preshared_key: "hQS+GkbTWfEhueLM8RJ2anjC4RxzdgL4dpTIetHf6GU=",
|
||||
remote_ip: %Postgrex.INET{address: {127, 0, 0, 1}},
|
||||
interface_address4: %Postgrex.INET{address: {10, 0, 0, 1}}
|
||||
})
|
||||
|
||||
@@ -85,8 +85,7 @@ defmodule FzHttp.DevicesTest do
|
||||
test "renders all peers", %{device: device} do
|
||||
assert Devices.to_peer_list() |> List.first() == %{
|
||||
public_key: device.public_key,
|
||||
allowed_ips: device.allowed_ips,
|
||||
preshared_key: device.preshared_key
|
||||
allowed_ips: device.allowed_ips
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -33,7 +33,6 @@ defmodule FzHttp.Fixtures do
|
||||
public_key: "test-pubkey",
|
||||
name: "factory",
|
||||
private_key: "test-privkey",
|
||||
preshared_key: "test-psk",
|
||||
server_public_key: "test-server-pubkey"
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ defmodule FzVpn.CLI.Live do
|
||||
|
||||
# Outputs the privkey, then pubkey on the next line
|
||||
@genkey_cmd "wg genkey | tee >(wg pubkey)"
|
||||
@genpsk_cmd "wg genpsk"
|
||||
|
||||
import FzCommon.CLI
|
||||
|
||||
@@ -34,15 +33,10 @@ defmodule FzVpn.CLI.Live do
|
||||
{privkey, pubkey}
|
||||
end
|
||||
|
||||
def add_peer(pubkey, _psk, ip) do
|
||||
def add_peer(pubkey, ip) do
|
||||
set("peer #{pubkey} allowed-ips #{ip}/32")
|
||||
end
|
||||
|
||||
def genpsk do
|
||||
exec!(@genpsk_cmd)
|
||||
|> String.trim()
|
||||
end
|
||||
|
||||
def pubkey(privkey) when is_nil(privkey), do: nil
|
||||
|
||||
def pubkey(privkey) when is_binary(privkey) do
|
||||
@@ -51,7 +45,10 @@ defmodule FzVpn.CLI.Live do
|
||||
end
|
||||
|
||||
def set(config_str) do
|
||||
exec!("#{wg()} set #{iface_name()} #{config_str}")
|
||||
# Empty config string results in invalid command
|
||||
if String.length(config_str) > 0 do
|
||||
exec!("#{wg()} set #{iface_name()} #{config_str}")
|
||||
end
|
||||
end
|
||||
|
||||
def show_latest_handshakes do
|
||||
|
||||
@@ -12,7 +12,6 @@ defmodule FzVpn.CLI.Sandbox do
|
||||
def setup, do: @default_returned
|
||||
def teardown, do: @default_returned
|
||||
def genkey, do: {rand_key(), rand_key()}
|
||||
def genpsk, do: rand_key()
|
||||
def pubkey(_privkey), do: rand_key()
|
||||
def exec!(_cmd), do: @default_returned
|
||||
def set(_conf_str), do: @default_returned
|
||||
|
||||
@@ -3,29 +3,14 @@ defmodule FzVpn.Config do
|
||||
Functions for managing the WireGuard configuration.
|
||||
"""
|
||||
|
||||
import FzVpn.CLI
|
||||
|
||||
defstruct peers: MapSet.new([])
|
||||
|
||||
def render(config) do
|
||||
"private-key #{private_key()} listen-port #{listen_port()} " <>
|
||||
Enum.join(
|
||||
for peer <- config.peers do
|
||||
"peer #{peer.public_key} allowed-ips #{peer.allowed_ips} preshared-key #{peer.preshared_key}"
|
||||
end,
|
||||
" "
|
||||
)
|
||||
end
|
||||
|
||||
def private_key do
|
||||
Application.get_env(:fz_vpn, :wireguard_private_key)
|
||||
end
|
||||
|
||||
def public_key do
|
||||
cli().pubkey(private_key())
|
||||
end
|
||||
|
||||
def listen_port do
|
||||
Application.get_env(:fz_vpn, :wireguard_port)
|
||||
Enum.join(
|
||||
for peer <- config.peers do
|
||||
"peer #{peer.public_key} allowed-ips #{peer.allowed_ips}"
|
||||
end,
|
||||
" "
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4,6 +4,5 @@ defmodule FzVpn.Peer do
|
||||
"""
|
||||
|
||||
defstruct public_key: nil,
|
||||
allowed_ips: "0.0.0.0/0,::/0",
|
||||
preshared_key: nil
|
||||
allowed_ips: "0.0.0.0/0,::/0"
|
||||
end
|
||||
|
||||
@@ -31,10 +31,9 @@ defmodule FzVpn.Server do
|
||||
|
||||
@impl true
|
||||
def handle_call(:create_device, _from, config) do
|
||||
server_pubkey = Config.public_key()
|
||||
server_pubkey = Application.get_env(:fz_vpn, :wireguard_public_key)
|
||||
{privkey, pubkey} = cli().genkey()
|
||||
psk = cli().genpsk()
|
||||
{:reply, {:ok, privkey, pubkey, server_pubkey, psk}, config}
|
||||
{:reply, {:ok, privkey, pubkey, server_pubkey}, config}
|
||||
end
|
||||
|
||||
@impl true
|
||||
@@ -53,7 +52,7 @@ defmodule FzVpn.Server do
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_cast({:device_created, pubkey, psk, ip}, config) do
|
||||
def handle_cast({:device_created, pubkey, ip}, config) do
|
||||
new_config =
|
||||
Map.put(
|
||||
config,
|
||||
@@ -61,7 +60,7 @@ defmodule FzVpn.Server do
|
||||
MapSet.put(config.peers, pubkey)
|
||||
)
|
||||
|
||||
cli().add_peer(pubkey, psk, ip)
|
||||
cli().add_peer(pubkey, ip)
|
||||
{:noreply, new_config}
|
||||
end
|
||||
|
||||
|
||||
@@ -2,14 +2,13 @@ defmodule FzVpn.ConfigTest do
|
||||
use ExUnit.Case, async: true
|
||||
alias FzVpn.{Config, Peer}
|
||||
|
||||
@default_config "private-key UAeZoaY95pKZE1Glq28sI2GJDfGGRFtlb4KC6rjY2Gs= listen-port 51820 "
|
||||
@populated_config "private-key UAeZoaY95pKZE1Glq28sI2GJDfGGRFtlb4KC6rjY2Gs= listen-port 51820 peer test-pubkey allowed-ips test-allowed-ips preshared-key test-preshared-key"
|
||||
@populated_config "peer test-pubkey allowed-ips test-allowed-ips"
|
||||
|
||||
describe "render" do
|
||||
test "renders default config" do
|
||||
config = %Config{}
|
||||
|
||||
assert Config.render(config) == @default_config
|
||||
assert Config.render(config) == ""
|
||||
end
|
||||
|
||||
test "renders populated config" do
|
||||
@@ -18,8 +17,7 @@ defmodule FzVpn.ConfigTest do
|
||||
MapSet.new([
|
||||
%Peer{
|
||||
public_key: "test-pubkey",
|
||||
allowed_ips: "test-allowed-ips",
|
||||
preshared_key: "test-preshared-key"
|
||||
allowed_ips: "test-allowed-ips"
|
||||
}
|
||||
])
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ defmodule FzVpn.ServerTest do
|
||||
|
||||
@tag stubbed_config: @empty
|
||||
test "generates new peer when requested", %{test_pid: test_pid} do
|
||||
assert {:ok, _, _, _, _} = GenServer.call(test_pid, :create_device)
|
||||
assert {:ok, _, _, _} = GenServer.call(test_pid, :create_device)
|
||||
# Peers aren't added to config until device is successfully created
|
||||
assert [] = MapSet.to_list(:sys.get_state(test_pid).peers)
|
||||
end
|
||||
|
||||
@@ -37,7 +37,7 @@ config :fz_wall,
|
||||
|
||||
# This will be changed per-env
|
||||
config :fz_vpn,
|
||||
wireguard_private_key: "UAeZoaY95pKZE1Glq28sI2GJDfGGRFtlb4KC6rjY2Gs=",
|
||||
wireguard_public_key: "cB2yQeCxHO/qCH8APoM2D2Anf4Yd7sRLyfS7su71K3M=",
|
||||
wireguard_interface_name: "wg-firezone",
|
||||
wireguard_port: "51820",
|
||||
wireguard_endpoint_ip: "127.0.0.1",
|
||||
|
||||
@@ -32,6 +32,7 @@ config :fz_http, FzHttpWeb.Endpoint,
|
||||
]
|
||||
|
||||
config :fz_vpn,
|
||||
wireguard_public_key: System.get_env("WIREGUARD_PUBLIC_KEY"),
|
||||
wg_path: "wg",
|
||||
cli: FzVpn.CLI.Live
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@ wg_path = System.fetch_env!("WG_PATH")
|
||||
encryption_key = System.fetch_env!("DATABASE_ENCRYPTION_KEY")
|
||||
secret_key_base = System.fetch_env!("SECRET_KEY_BASE")
|
||||
live_view_signing_salt = System.fetch_env!("LIVE_VIEW_SIGNING_SALT")
|
||||
private_key = System.fetch_env!("WIREGUARD_PRIVATE_KEY")
|
||||
|
||||
# Password is not needed if using bundled PostgreSQL, so use nil if it's not set.
|
||||
database_password = System.get_env("DATABASE_PASSWORD")
|
||||
@@ -78,8 +77,7 @@ config :fz_wall,
|
||||
config :fz_vpn,
|
||||
wireguard_interface_name: wireguard_interface_name,
|
||||
wireguard_port: wireguard_port,
|
||||
wireguard_endpoint_ip: wireguard_endpoint_ip,
|
||||
wireguard_private_key: private_key
|
||||
wireguard_endpoint_ip: wireguard_endpoint_ip
|
||||
|
||||
config :fz_http,
|
||||
admin_email: admin_email,
|
||||
|
||||
@@ -62,8 +62,7 @@ default['firezone']['group'] = 'firezone'
|
||||
# Used for generating URLs that point back to this application.
|
||||
default['firezone']['url_host'] = node['firezone']['fqdn']
|
||||
# Email for the primary admin user.
|
||||
default['firezone']['admin_email'] =
|
||||
"firezone@#{node['firezone']['fqdn']}"
|
||||
default['firezone']['admin_email'] = "firezone@localhost"
|
||||
|
||||
# ## Enterprise
|
||||
#
|
||||
|
||||
@@ -102,6 +102,8 @@ class Firezone
|
||||
SecureRandom.base64(8)
|
||||
end
|
||||
|
||||
node.override['firezone']['wireguard_public_key'] =
|
||||
`echo '#{wireguard_private_key}' | #{node['firezone']['wireguard_private_key']}/embedded/bin/wg pubkey`.chomp
|
||||
|
||||
secrets = {
|
||||
'secret_key_base' => secret_key_base,
|
||||
@@ -228,11 +230,11 @@ class Firezone
|
||||
'WIREGUARD_INTERFACE_NAME' => attributes['wireguard']['interface_name'],
|
||||
'WIREGUARD_ENDPOINT_IP' => attributes['wireguard']['endpoint_ip'],
|
||||
'WIREGUARD_PORT' => attributes['wireguard']['port'].to_s,
|
||||
'WIREGUARD_PUBLIC_KEY' => attributes['wireguard_public_key'],
|
||||
|
||||
# secrets
|
||||
'SECRET_KEY_BASE' => attributes['secret_key_base'],
|
||||
'LIVE_VIEW_SIGNING_SALT' => attributes['live_view_signing_salt'],
|
||||
'WIREGUARD_PRIVATE_KEY' => attributes['wireguard_private_key'],
|
||||
'DATABASE_ENCRYPTION_KEY' => attributes['database_encryption_key']
|
||||
}
|
||||
|
||||
|
||||
@@ -91,3 +91,11 @@ file "#{node['firezone']['config_directory']}/secrets.json" do
|
||||
group node['firezone']['group']
|
||||
mode '0600'
|
||||
end
|
||||
|
||||
file "#{node['firezone']['var_directory']}/cache/wg_private_key" do
|
||||
owner 'root'
|
||||
group 'root'
|
||||
mode '0600'
|
||||
content node['firezone']['wireguard_private_key']
|
||||
action :create_if_missing
|
||||
end
|
||||
|
||||
@@ -46,15 +46,6 @@ execute 'setup_wireguard_ip' do
|
||||
command "ip address replace #{if_addr} dev #{wg_interface}"
|
||||
end
|
||||
|
||||
file 'write_private_key_file' do
|
||||
path private_key_path
|
||||
owner 'root'
|
||||
group 'root'
|
||||
mode '0600'
|
||||
content node['firezone']['wireguard_private_key']
|
||||
action :create_if_missing
|
||||
end
|
||||
|
||||
execute 'set_wireguard_interface_private_key' do
|
||||
command "#{wg_path} set #{wg_interface} private-key #{private_key_path}"
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user