Skip to content

Commit

Permalink
Add trusted_mirror_url config (#956)
Browse files Browse the repository at this point in the history
Co-authored-by: Eric Meadows-Jönsson <[email protected]>
  • Loading branch information
Benjamin-Philip and ericmj authored Feb 1, 2023
1 parent 0c81661 commit fc69730
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 60 deletions.
59 changes: 32 additions & 27 deletions lib/hex/repo.ex
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,19 @@ defmodule Hex.Repo do
repos = Hex.State.fetch!(:repos)

case Map.fetch(repos, repo) do
{:ok, config} ->
{:ok, config} when repo == "hexpm" ->
trusted_mirror_url = Hex.State.fetch!(:trusted_mirror_url)
mirror_url = Hex.State.fetch!(:mirror_url)

if repo == "hexpm" and mirror_url do
{:ok, Map.put(config, :url, mirror_url)}
else
{:ok, config}
end
config =
config
|> Map.put(:url, trusted_mirror_url || mirror_url || config.url)
|> Map.put(:trusted, trusted_mirror_url != nil or mirror_url == nil)

{:ok, config}

{:ok, config} ->
{:ok, config}

:error ->
fetch_organization_fallback(repo, repos)
Expand All @@ -55,13 +60,15 @@ defmodule Hex.Repo do
|> Map.put(:url, url)
|> Map.put(:public_key, public_key)
|> Map.put(:auth_key, auth_key)
|> Map.put(:trusted, auth_key)
end

def default_hexpm_repo(auth_key \\ Hex.State.fetch!(:repos_key)) do
%{
url: @hexpm_url,
public_key: @hexpm_public_key,
auth_key: auth_key
auth_key: auth_key,
trusted: true
}
end

Expand Down Expand Up @@ -171,6 +178,11 @@ defmodule Hex.Repo do
HTTP.request(:get, tarball_url(repo, package, version), headers, nil)
end

def get_public_key(repo) do
headers = auth_headers(repo)
HTTP.request(:get, public_key_url(repo), headers, nil)
end

def verify(body, repo) do
public_key = get_repo(repo).public_key

Expand Down Expand Up @@ -210,17 +222,23 @@ defmodule Hex.Repo do
config.url <> "/tarballs/#{URI.encode(package)}-#{URI.encode(version)}.tar"
end

defp public_key_url(repo), do: repo.url <> "/public_key"

defp etag_headers(nil), do: %{}
defp etag_headers(etag), do: %{~c"if-none-match" => String.to_charlist(etag)}

defp auth_headers(repo) do
repo = get_repo(repo)
defp auth_headers(repo) when is_binary(repo) or repo == nil do
repo
|> get_repo()
|> auth_headers()
end

defp auth_headers(%{trusted: true, auth_key: key}) when is_binary(key) do
%{~c"authorization" => String.to_charlist(key)}
end

if key = repo.auth_key do
%{~c"authorization" => String.to_charlist(key)}
else
%{}
end
defp auth_headers(%{trusted: _, auth_key: _}) do
%{}
end

defp parse_csv(body) do
Expand Down Expand Up @@ -323,17 +341,4 @@ defmodule Hex.Repo do
defp repo_name(name) do
name |> split_repo_name() |> List.last()
end

def get_public_key(repo_url, auth_key) do
auth_headers =
if auth_key do
%{~c"authorization" => String.to_charlist(auth_key)}
else
%{}
end

HTTP.request(:get, public_key_url(repo_url), auth_headers, nil)
end

defp public_key_url(repo_url), do: repo_url <> "/public_key"
end
29 changes: 12 additions & 17 deletions lib/hex/state.ex
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ defmodule Hex.State do
config: [:mirror_url],
fun: {__MODULE__, :trim_slash}
},
trusted_mirror_url: %{
env: ["HEX_TRUSTED_MIRROR_URL", "HEX_TRUSTED_MIRROR"],
config: [:trusted_mirror_url],
fun: {__MODULE__, :trim_slash}
},
offline: %{
env: ["HEX_OFFLINE"],
config: [:offline],
Expand Down Expand Up @@ -224,9 +229,10 @@ defmodule Hex.State do
end

defp load_config_value(global_config, project_config, spec) do
env = System.get_env()

result =
load_env(spec[:env]) ||
load_env_path_join(spec[:env_path_join]) ||
load_env(spec[:env], env) ||
load_project_config(project_config, spec[:config]) ||
load_global_config(global_config, spec[:config])

Expand Down Expand Up @@ -271,22 +277,11 @@ defmodule Hex.State do
|> Path.join("hex.config")
end

defp load_env(keys) do
defp load_env(keys, env) do
Enum.find_value(keys || [], fn key ->
if value = System.get_env(key) do
{{:env, key}, value}
else
nil
end
end)
end

defp load_env_path_join(keys) do
Enum.find_value(keys || [], fn {key, prefix} ->
if value = System.get_env(key) do
{{:env_path_join, {key, prefix}}, Path.join(value, prefix)}
else
nil
case Map.fetch(env, key) do
{:ok, value} -> {{:env, key}, value}
:error -> nil
end
end)
end
Expand Down
18 changes: 9 additions & 9 deletions lib/mix/tasks/hex.config.ex
Original file line number Diff line number Diff line change
Expand Up @@ -40,23 +40,26 @@ defmodule Mix.Tasks.Hex.Config do
origin. Can be overridden by setting the environment variable
`HEX_NO_VERIFY_REPO_ORIGIN` (Default: `false`)
* `http_proxy` - HTTP proxy server. Can be overridden by setting the
environment variable `HTTP_PROXY` (Default: `nil`)
environment variable `HTTP_PROXY`
* `https_proxy` - HTTPS proxy server. Can be overridden by setting the
environment variable `HTTPS_PROXY` (Default: `nil`)
environment variable `HTTPS_PROXY`
* `no_proxy` - A comma separated list of hostnames that will not be proxied,
asterisks can be used as wildcards. Can be overridden by setting the
environment variable `no_proxy` or `NO_PROXY` (Default: `nil`)
environment variable `no_proxy` or `NO_PROXY`
* `http_concurrency` - Limits the number of concurrent HTTP requests in
flight. Can be overridden by setting the environment variable
`HEX_HTTP_CONCURRENCY` (Default: `8`)
* `http_timeout` - Sets the timeout for HTTP requests in seconds. Can be
overridden by setting the environment variable `HEX_HTTP_TIMEOUT`
(Default: `nil`)
* `mirror_url` - Hex mirror URL. Can be overridden by setting the
environment variable `HEX_MIRROR` (Default: `nil`)
environment variable `HEX_TRUSTED_MIRROR`
* `trusted_mirror_url` - Hex mirror URL. Unlike `mirror_url`, this mirror is
"trusted", secrets such as authentication information will be sent to the
mirror. Can be overridden by setting the environment variable
`HEX_TRUSTED_MIRROR`
* `cacerts_path` - Path to the CA certificate store PEM file. If not set,
a CA bundle that ships with Hex is used. Can be overridden by setting the
environment variable `HEX_CACERTS_PATH`. (Default: `nil`)
environment variable `HEX_CACERTS_PATH`
* `no_short_urls` - If set to true Hex will not
shorten any links. Can be overridden by setting the environment variable
`HEX_NO_SHORT_URLS` (Default: `false`)
Expand Down Expand Up @@ -191,9 +194,6 @@ defmodule Mix.Tasks.Hex.Config do
{:ok, {{:project_config, _key}, value}} ->
print_value(key, value, verbose, "(using `mix.exs`)")

{:ok, {{:env_path_join, {env_var, _prefix}}, value}} ->
print_value(key, value, verbose, "(using `#{env_var}`)")

{:ok, {kind, value}} when kind in [:default, :computed] ->
print_value(key, value, verbose, "(default)")

Expand Down
7 changes: 5 additions & 2 deletions lib/mix/tasks/hex.repo.ex
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,8 @@ defmodule Mix.Tasks.Hex.Repo do
url: url,
public_key: nil,
fetch_public_key: nil,
auth_key: nil
auth_key: nil,
trusted: true
}
|> Map.merge(Map.new(opts))
|> Map.put(:public_key, public_key)
Expand Down Expand Up @@ -214,7 +215,9 @@ defmodule Mix.Tasks.Hex.Repo do
defp fetch_public_key(nil, _, _), do: nil

defp fetch_public_key(fingerprint, repo_url, auth_key) do
case Hex.Repo.get_public_key(repo_url, auth_key) do
repo_config = %{url: repo_url, auth_key: auth_key, trusted: true}

case Hex.Repo.get_public_key(repo_config) do
{:ok, {200, key, _}} ->
if show_public_key(key) == fingerprint do
key
Expand Down
11 changes: 6 additions & 5 deletions test/hex/repo_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -55,19 +55,20 @@ defmodule Hex.RepoTest do
Bypass.expect(bypass, fn %Plug.Conn{request_path: path} = conn ->
case path do
"/public_key" ->
assert Plug.Conn.get_req_header(conn, "authorization") == ["key"]
Plug.Conn.resp(conn, 200, hexpm.public_key)

"/not_found/public_key" ->
assert Plug.Conn.get_req_header(conn, "authorization") == []
Plug.Conn.resp(conn, 404, "not found")
end
end)

assert {:ok, {200, public_key, _}} =
Hex.Repo.get_public_key("http://localhost:#{bypass.port}", nil)

config = %{url: "http://localhost:#{bypass.port}", auth_key: "key", trusted: true}
assert {:ok, {200, public_key, _}} = Hex.Repo.get_public_key(config)
assert public_key == hexpm.public_key

assert {:ok, {404, "not found", _}} =
Hex.Repo.get_public_key("http://localhost:#{bypass.port}/not_found", nil)
config = %{url: "http://localhost:#{bypass.port}/not_found", auth_key: "key", trusted: false}
assert {:ok, {404, "not found", _}} = Hex.Repo.get_public_key(config)
end
end
1 change: 1 addition & 0 deletions test/mix/tasks/hex.config_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ defmodule Mix.Tasks.Hex.ConfigTest do
assert_received {:mix_shell, :info, ["http_concurrency: 8 (default)"]}
assert_received {:mix_shell, :info, ["http_timeout: nil (default)"]}
assert_received {:mix_shell, :info, ["mirror_url: nil (default)"]}
assert_received {:mix_shell, :info, ["trusted_mirror_url: nil (default)"]}
assert_received {:mix_shell, :info, ["config_home:" <> _]}
assert_received {:mix_shell, :info, ["no_short_urls: false (default)"]}
end)
Expand Down

0 comments on commit fc69730

Please sign in to comment.