This repository has been archived by the owner on Jun 11, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
241fb6c
commit a1404e3
Showing
12 changed files
with
884 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
# credo:disable-for-this-file Credo.Check.Refactor.FunctionArity | ||
defmodule Helix.Log.Action.Flow.Recover do | ||
|
||
alias Helix.Event | ||
alias Helix.Entity.Model.Entity | ||
alias Helix.Network.Model.Connection | ||
alias Helix.Network.Model.Tunnel | ||
alias Helix.Server.Model.Server | ||
alias Helix.Software.Model.File | ||
alias Helix.Log.Model.Log | ||
|
||
alias Helix.Log.Process.Recover, as: LogRecoverProcess | ||
|
||
@spec global( | ||
Server.t, | ||
Server.t, | ||
File.t, | ||
Entity.id, | ||
{Tunnel.t, Connection.ssh} | nil, | ||
Event.relay | ||
) :: | ||
term | ||
def global( | ||
gateway = %Server{}, | ||
endpoint = %Server{}, | ||
recover = %File{software_type: :log_recover}, | ||
entity_id = %Entity.ID{}, | ||
conn, | ||
relay | ||
) do | ||
start_process(gateway, endpoint, nil, recover, entity_id, conn, relay) | ||
end | ||
|
||
@spec custom( | ||
Server.t, | ||
Server.t, | ||
Log.t, | ||
File.t, | ||
Entity.id, | ||
{Tunnel.t, Connection.ssh} | nil, | ||
Event.relay | ||
) :: | ||
term | ||
def custom( | ||
gateway = %Server{}, | ||
endpoint = %Server{}, | ||
log = %Log{}, | ||
recover = %File{software_type: :log_recover}, | ||
entity_id = %Entity.ID{}, | ||
conn, | ||
relay | ||
) do | ||
start_process( | ||
gateway, endpoint, log, recover, entity_id, conn, relay | ||
) | ||
end | ||
|
||
defp start_process( | ||
gateway = %Server{}, | ||
endpoint = %Server{}, | ||
log, | ||
recover = %File{software_type: :log_recover}, | ||
entity_id = %Entity.ID{}, | ||
conn_info, | ||
relay | ||
) do | ||
method = | ||
if is_nil(log) do | ||
:global | ||
else | ||
:custom | ||
end | ||
|
||
{network_id, ssh} = | ||
if is_nil(conn_info) do | ||
{nil, nil} | ||
else | ||
{tunnel, ssh} = conn_info | ||
{tunnel.network_id, ssh} | ||
end | ||
|
||
params = %{} | ||
|
||
meta = | ||
%{ | ||
recover: recover, | ||
log: log, | ||
method: method, | ||
ssh: ssh, | ||
entity_id: entity_id, | ||
network_id: network_id | ||
} | ||
|
||
LogRecoverProcess.execute(gateway, endpoint, params, meta, relay) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
defmodule Helix.Log.Henforcer.Log.Recover do | ||
|
||
import Helix.Henforcer | ||
|
||
alias Helix.Server.Henforcer.Server, as: ServerHenforcer | ||
alias Helix.Server.Model.Server | ||
alias Helix.Software.Henforcer.File, as: FileHenforcer | ||
alias Helix.Software.Model.File | ||
alias Helix.Log.Henforcer.Log, as: LogHenforcer | ||
alias Helix.Log.Model.Log | ||
|
||
@type can_recover_global_relay :: %{gateway: Server.t, recover: File.t} | ||
@type can_recover_global_relay_partial :: map | ||
@type can_recover_global_error :: | ||
ServerHenforcer.server_exists_error | ||
| exists_recover_error | ||
|
||
@spec can_recover_global?(Server.id) :: | ||
{true, can_recover_global_relay} | ||
| can_recover_global_error | ||
@doc """ | ||
Henforces that the player can start a global LogRecover process. | ||
In order to recover globally, all a user needs to have is: | ||
- SSH access to the server | ||
- a valid LogRecover file on his gateway filesystem | ||
""" | ||
def can_recover_global?(gateway_id) do | ||
with \ | ||
{true, r1} <- ServerHenforcer.server_exists?(gateway_id), | ||
r1 = replace(r1, :server, :gateway), | ||
gateway = r1.gateway, | ||
{true, r2} <- exists_recover?(gateway), | ||
r2 = replace(r2, :file, :recover, only: true) | ||
do | ||
[r1, r2] | ||
|> relay() | ||
|> reply_ok() | ||
end | ||
end | ||
|
||
@type can_recover_custom_relay :: | ||
%{log: Log.t, gateway: Server.t, recover: File.t} | ||
@type can_recover_custom_relay_partial :: map | ||
@type can_recover_custom_error :: | ||
LogHenforcer.log_exists_error | ||
| LogHenforcer.belongs_to_server_error | ||
| ServerHenforcer.server_exists_error | ||
| exists_recover_error | ||
|
||
@spec can_recover_custom?(Log.id, Server.id, Server.id) :: | ||
{true, can_recover_custom_relay} | ||
| can_recover_custom_error | ||
@doc """ | ||
Henforces that the player can start a custom LogRecover process. | ||
In order to recover a specific (custom) log, the player must have the same | ||
requirements of a `global` recover (SSH access and valid LogRecover file), and | ||
also the given `log_id` must exist, and it must exist on the target server. | ||
""" | ||
def can_recover_custom?(log_id = %Log.ID{}, gateway_id, target_id) do | ||
with \ | ||
{true, r1} <- LogHenforcer.log_exists?(log_id), | ||
log = r1.log, | ||
|
||
{true, _} <- LogHenforcer.belongs_to_server?(log, target_id), | ||
|
||
{true, r2} <- ServerHenforcer.server_exists?(gateway_id), | ||
r2 = replace(r2, :server, :gateway), | ||
gateway = r2.gateway, | ||
|
||
{true, r3} <- exists_recover?(gateway), | ||
r3 = replace(r3, :file, :recover, only: true) | ||
do | ||
[r1, r2, r3] | ||
|> relay() | ||
|> reply_ok() | ||
end | ||
end | ||
|
||
@type exists_recover_relay :: FileHenforcer.exists_software_module_relay | ||
@type exists_recover_relay_partial :: | ||
FileHenforcer.exists_software_module_relay_partial | ||
@type exists_recover_error :: | ||
{false, {:recover, :not_found}, exists_recover_relay_partial} | ||
|
||
@spec exists_recover?(Server.t) :: | ||
{true, exists_recover_relay} | ||
| exists_recover_error | ||
@doc """ | ||
Ensures that exists a Recover file on `server`, sorting the result by `module` | ||
(only `:log_recover` in this context). | ||
It's simply a wrapper over `FileHenforcer.exists_software_module?` used to | ||
generate a more meaningful error message ("recover_not_found") instead of | ||
"module_not_found". | ||
""" | ||
def exists_recover?(server = %Server{}) do | ||
henforce_else( | ||
FileHenforcer.exists_software_module?(:log_recover, server), | ||
{:recover, :not_found} | ||
) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
defmodule Helix.Log.Public.Recover do | ||
|
||
alias Helix.Log.Action.Flow.Recover, as: RecoverFlow | ||
|
||
defdelegate global(gateway, endpoint, recover, entity, conn_info, relay), | ||
to: RecoverFlow | ||
|
||
defdelegate custom(gateway, endpoint, log, recover, entity, conn_info, relay), | ||
to: RecoverFlow | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
import Helix.Websocket.Request | ||
|
||
request Helix.Log.Websocket.Requests.Recover do | ||
@moduledoc """ | ||
`LogRecoverRequest` is called when the player wants to recover a log. It may | ||
either be a `global` recovery, in which case a recoverable log is randomly | ||
selected from all logs within the server, or it may be a `custom` recovery, | ||
in which case a specific log to be recovered is defined by the player. | ||
""" | ||
|
||
import HELL.Macros | ||
|
||
alias Helix.Server.Query.Server, as: ServerQuery | ||
alias Helix.Log.Henforcer.Log.Recover, as: LogRecoverHenforcer | ||
alias Helix.Log.Model.Log | ||
alias Helix.Log.Public.Recover, as: RecoverPublic | ||
|
||
def check_params(request, socket) do | ||
case request.unsafe["method"] do | ||
"global" -> | ||
check_params_global(request, socket) | ||
|
||
"custom" -> | ||
check_params_custom(request, socket) | ||
|
||
_ -> | ||
reply_error(request, "bad_method") | ||
end | ||
end | ||
|
||
defp check_params_global(request, _socket), | ||
do: update_params(request, %{method: :global}, reply: true) | ||
|
||
defp check_params_custom(request, _socket) do | ||
with \ | ||
{:ok, log_id} <- Log.ID.cast(request.unsafe["log_id"]) | ||
do | ||
params = %{method: :custom, log_id: log_id} | ||
|
||
update_params(request, params, reply: true) | ||
else | ||
_ -> | ||
bad_request(request) | ||
end | ||
end | ||
|
||
def check_permissions(request = %{params: %{method: :global}}, socket) do | ||
gateway_id = socket.assigns.gateway.server_id | ||
|
||
case LogRecoverHenforcer.can_recover_global?(gateway_id) do | ||
{true, relay} -> | ||
meta = %{gateway: relay.gateway, recover: relay.recover} | ||
update_meta(request, meta, reply: true) | ||
|
||
{false, reason, _} -> | ||
reply_error(request, reason) | ||
end | ||
end | ||
|
||
def check_permissions(request = %{params: %{method: :custom}}, socket) do | ||
log_id = request.params.log_id | ||
gateway_id = socket.assigns.gateway.server_id | ||
target_id = socket.assigns.destination.server_id | ||
|
||
can_recover? = | ||
LogRecoverHenforcer.can_recover_custom?(log_id, gateway_id, target_id) | ||
|
||
case can_recover? do | ||
{true, relay} -> | ||
meta = %{gateway: relay.gateway, recover: relay.recover, log: relay.log} | ||
update_meta(request, meta, reply: true) | ||
|
||
{false, reason, _} -> | ||
reply_error(request, reason) | ||
end | ||
end | ||
|
||
def handle_request(request, socket) do | ||
entity_id = socket.assigns.entity_id | ||
recover = request.meta.recover | ||
gateway = request.meta.gateway | ||
relay = request.relay | ||
|
||
{target, conn_info} = | ||
if socket.assigns.meta.access == :local do | ||
{gateway, nil} | ||
else | ||
{ | ||
ServerQuery.fetch(socket.assigns.destination.server_id), | ||
{socket.assigns.tunnel, socket.assigns.ssh} | ||
} | ||
end | ||
|
||
hespawn fn -> | ||
if request.params.method == :global do | ||
RecoverPublic.global( | ||
gateway, target, recover, entity_id, conn_info, relay | ||
) | ||
else | ||
log = request.meta.log | ||
|
||
RecoverPublic.custom( | ||
gateway, target, log, recover, entity_id, conn_info, relay | ||
) | ||
end | ||
end | ||
|
||
reply_ok(request) | ||
end | ||
|
||
render_empty() | ||
end |
Oops, something went wrong.