Packages
corex
0.1.0-beta.5
0.1.2
0.1.1
0.1.0
0.1.0-rc.1
0.1.0-rc.0
0.1.0-beta.5
0.1.0-beta.4
0.1.0-beta.3
0.1.0-beta.2
0.1.0-beta.1
0.1.0-alpha.33
0.1.0-alpha.32
0.1.0-alpha.31
0.1.0-alpha.30
0.1.0-alpha.29
0.1.0-alpha.28
0.1.0-alpha.27
0.1.0-alpha.26
0.1.0-alpha.25
0.1.0-alpha.24
0.1.0-alpha.23
0.1.0-alpha.22
0.1.0-alpha.21
0.1.0-alpha.20
0.1.0-alpha.19
0.1.0-alpha.18
0.1.0-alpha.17
0.1.0-alpha.16
0.1.0-alpha.15
0.1.0-alpha.14
0.1.0-alpha.13
0.1.0-alpha.12
0.1.0-alpha.11
0.1.0-alpha.10
0.1.0-alpha.9
0.1.0-alpha.8
0.1.0-alpha.7
0.1.0-alpha.6
0.1.0-alpha.5
0.1.0-alpha.4
0.1.0-alpha.3
0.1.0-alpha.2
0.1.0-alpha.1
Accessible and unstyled UI components library written in Elixir and TypeScript that integrates Zag.js state machines into the Phoenix Framework.
Current section
Files
Jump to
Current section
Files
lib/mcp/plug.ex
defmodule Corex.MCP do
@moduledoc false
@behaviour Plug
require Logger
@impl true
def init(opts) when is_list(opts) do
maybe_silence_mcp_server_logs()
%{
allow_remote_access: Keyword.get(opts, :allow_remote_access, false)
}
end
def init(%{} = opts) do
maybe_silence_mcp_server_logs()
Map.merge(%{allow_remote_access: false}, opts)
end
defp maybe_silence_mcp_server_logs do
if Application.get_env(:corex, :debug) do
:ok
else
Logger.put_module_level(Corex.MCP.Server, :none)
end
end
@impl true
def call(%Plug.Conn{path_info: ["corex" | rest]} = conn, config) do
conn
|> validate!()
|> Plug.Conn.put_private(:corex_mcp_config, config)
|> Plug.forward(rest, Corex.MCP.Router, [])
|> Plug.Conn.halt()
end
def call(conn, _opts) do
conn
|> Plug.Conn.register_before_send(fn conn ->
conn
|> maybe_rewrite_csp()
|> Plug.Conn.delete_resp_header("x-frame-options")
end)
end
defp validate!(conn) do
if live_reload_enabled?(conn) or request_body_parsed?(conn) do
raise "plug Corex.MCP is runnning too late, after the request body has been parsed. " <>
"Make sure to place \"plug Corex.MCP\" before the \"if code_reloading? do\" block"
end
conn
end
defp live_reload_enabled?(conn) do
match?(%{phoenix_live_reload: true}, conn.private)
end
defp request_body_parsed?(conn) do
not match?(%Plug.Conn.Unfetched{}, conn.body_params)
end
defp maybe_rewrite_csp(conn) do
case Plug.Conn.get_resp_header(conn, "content-security-policy") do
[csp | _] ->
csp = rewrite_csp(csp)
Plug.Conn.put_resp_header(conn, "content-security-policy", csp)
_ ->
conn
end
end
defp rewrite_csp(csp) do
policy_directives = String.split(csp, ";", trim: true)
for policy_directive <- policy_directives,
policy_directive = String.trim(policy_directive),
not String.starts_with?(policy_directive, "frame-ancestors") do
rewrite_csp_directive(policy_directive)
end
|> Enum.join("; ")
end
defp rewrite_csp_directive(policy_directive) do
case String.split(policy_directive, " ", parts: 2) do
["script-src", directives] ->
script_src_with_unsafe_eval(directives)
[policy, directives] ->
"#{policy} #{directives}"
[leftover] ->
leftover
end
end
defp script_src_with_unsafe_eval(directives) do
case :binary.match(directives, "'unsafe-eval'") do
:nomatch -> "script-src 'unsafe-eval' #{directives}"
_ -> "script-src #{directives}"
end
end
end