Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion backend/config/dev.exs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,25 @@ url_host = System.get_env("URL_HOST", "localhost")
url_port = System.get_env("URL_PORT", "4000")
url_scheme = System.get_env("URL_SCHEME", "http")

check_origin =
case System.get_env("CHECK_ORIGIN_ALLOWED_ORIGINS") do
nil ->
["//localhost", "//127.0.0.1"]

raw_origins ->
raw_origins
|> String.split(",", trim: true)
|> Enum.map(&String.trim/1)
|> Enum.reject(&(&1 == ""))
end

database = %{
username: System.get_env("DATABASE_USERNAME", "postgres"),
password: System.get_env("DATABASE_PASSWORD", "postgres"),
hostname: System.get_env("DATABASE_HOSTNAME", "localhost"),
name: System.get_env("DATABASE_NAME", "edgehog_dev")
}

config :azurex, Azurex.Blob.Config,
api_url: "http://localhost:10000/devstoreaccount1",
default_container: "edgehog",
Expand Down Expand Up @@ -59,7 +78,7 @@ config :edgehog, EdgehogWeb.Endpoint,
scheme: url_scheme,
port: url_port
],
check_origin: false,
check_origin: check_origin,
code_reloader: true,
debug_errors: true,
secret_key_base: "uEb3NXr0KodsrjUUUo98VBEExFFAolxlfOW7ZzP/OGgd1R2pDhwMddZXjvUp/3MW",
Expand Down
18 changes: 18 additions & 0 deletions backend/config/runtime.exs
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,23 @@ if config_env() == :prod do
url_port = System.get_env("URL_PORT", "443")
url_scheme = System.get_env("URL_SCHEME", "https")

check_origin_default = ["#{url_scheme}://#{url_host}:#{url_port}"]

check_origin =
case System.get_env("CHECK_ORIGIN_ALLOWED_ORIGINS") do
nil ->
check_origin_default

raw_origins ->
parsed_origins =
raw_origins
|> String.split(",", trim: true)
|> Enum.map(&String.trim/1)
|> Enum.reject(&(&1 == ""))

if parsed_origins == [], do: check_origin_default, else: parsed_origins
end

forwarder_secure_sessions? =
System.get_env("EDGEHOG_FORWARDER_SECURE_SESSIONS", "true") == "true"

Expand Down Expand Up @@ -241,6 +258,7 @@ if config_env() == :prod do
scheme: url_scheme,
port: url_port
],
check_origin: check_origin,
secret_key_base: secret_key_base

if forwarder_hostname != nil &&
Expand Down
3 changes: 1 addition & 2 deletions backend/lib/edgehog_web/endpoint.ex
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ defmodule EdgehogWeb.Endpoint do
]

socket "/socket", EdgehogWeb.GqlSocket,
# TODO: Enable `check_origin` (and configure allowed origins) to mitigate Cross-Site WebSocket Hijacking.
websocket: [connect_info: [:peer_data, :x_headers], check_origin: false],
websocket: [connect_info: [:peer_data, :x_headers]],
longpoll: [connect_info: [:peer_data, :x_headers]]

plug PlugHeartbeat, path: "/health"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
#
# This file is part of Edgehog.
#
# Copyright 2026 SECO Mind Srl
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#

defmodule EdgehogWeb.Schema.Subscriptions.CheckOriginConfigTest do
use ExUnit.Case, async: false

defp read_endpoint_config!(config_file, env) do
config_file
|> Config.Reader.read!(env: env, target: :host)
|> Keyword.get(:edgehog, [])
|> Keyword.fetch!(EdgehogWeb.Endpoint)
end

defp with_env(overrides, fun) do
previous = for {key, _value} <- overrides, into: %{}, do: {key, System.get_env(key)}

Enum.each(overrides, fn
{key, nil} -> System.delete_env(key)
{key, value} -> System.put_env(key, value)
end)

try do
fun.()
after
Enum.each(previous, fn
{key, nil} -> System.delete_env(key)
{key, value} -> System.put_env(key, value)
end)
end
end

describe "config/dev.exs check_origin" do
test "defaults to localhost origins when env var is not set" do
with_env([{"CHECK_ORIGIN_ALLOWED_ORIGINS", nil}], fn ->
endpoint = read_endpoint_config!("config/dev.exs", :dev)

assert Keyword.fetch!(endpoint, :check_origin) == ["//localhost", "//127.0.0.1"]
end)
end

test "uses comma-separated CHECK_ORIGIN_ALLOWED_ORIGINS" do
with_env(
[
{"CHECK_ORIGIN_ALLOWED_ORIGINS", "http://localhost:5173, http://edgehog.localhost"}
],
fn ->
endpoint = read_endpoint_config!("config/dev.exs", :dev)

assert Keyword.fetch!(endpoint, :check_origin) == [
"http://localhost:5173",
"http://edgehog.localhost"
]
end
)
end
end

describe "config/runtime.exs check_origin" do
test "defaults to URL_SCHEME://URL_HOST:URL_PORT in prod" do
with_env(
[
{"DATABASE_USERNAME", "postgres"},
{"DATABASE_PASSWORD", "postgres"},
{"DATABASE_HOSTNAME", "localhost"},
{"DATABASE_NAME", "edgehog"},
{"SECRET_KEY_BASE", "test_secret_key_base"},
{"URL_HOST", "api.edgehog.localhost"},
{"URL_SCHEME", "https"},
{"URL_PORT", "443"},
{"CHECK_ORIGIN_ALLOWED_ORIGINS", nil}
],
fn ->
endpoint = read_endpoint_config!("config/runtime.exs", :prod)

assert Keyword.fetch!(endpoint, :check_origin) == ["https://api.edgehog.localhost:443"]
end
)
end

test "uses CHECK_ORIGIN_ALLOWED_ORIGINS in prod when provided" do
with_env(
[
{"DATABASE_USERNAME", "postgres"},
{"DATABASE_PASSWORD", "postgres"},
{"DATABASE_HOSTNAME", "localhost"},
{"DATABASE_NAME", "edgehog"},
{"SECRET_KEY_BASE", "test_secret_key_base"},
{"URL_HOST", "api.edgehog.localhost"},
{"URL_SCHEME", "https"},
{"URL_PORT", "443"},
{"CHECK_ORIGIN_ALLOWED_ORIGINS", "https://ui.edgehog.localhost, https://ops.edgehog.localhost"}
],
fn ->
endpoint = read_endpoint_config!("config/runtime.exs", :prod)

assert Keyword.fetch!(endpoint, :check_origin) == [
"https://ui.edgehog.localhost",
"https://ops.edgehog.localhost"
]
end
)
end
end
end