Skip to content

Commit fad48c4

Browse files
voltoneJosé Valim
authored andcommitted
Warn when using unsafe URL local installs
1 parent 215229c commit fad48c4

File tree

7 files changed

+111
-24
lines changed

7 files changed

+111
-24
lines changed

lib/mix/lib/mix/local/installer.ex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ defmodule Mix.Local.Installer do
107107
module.install(basename, binary, previous_files)
108108

109109
:badpath ->
110-
Mix.raise("Expected #{inspect(src)} to be a URL or a local file path")
110+
Mix.raise("Expected #{inspect(src)} to be a local file path")
111111

112112
{:local, message} ->
113113
Mix.raise(message)
@@ -164,7 +164,7 @@ defmodule Mix.Local.Installer do
164164
cond do
165165
local_path?(url_or_path) -> {:local, url_or_path}
166166
file_url?(url_or_path) -> {:url, url_or_path}
167-
true -> {:error, "Expected #{inspect(url_or_path)} to be a URL or a local file path"}
167+
true -> {:error, "Expected #{inspect(url_or_path)} to be a local file path"}
168168
end
169169
end
170170

lib/mix/lib/mix/tasks/archive.install.ex

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ defmodule Mix.Tasks.Archive.Install do
1212
1313
mix do archive.build, archive.install
1414
15-
If an argument is provided, it should be a local path or a URL to a
15+
If an argument is provided, it should be a local path to a
1616
prebuilt archive, a Git repository, a GitHub repository, or a Hex
1717
package.
1818
@@ -35,13 +35,12 @@ defmodule Mix.Tasks.Archive.Install do
3535
mix some_task
3636
3737
Note that installing via Git, GitHub, or Hex fetches the source
38-
of the archive and builds it, while using a URL or a local path
39-
fetches a pre-built archive.
38+
of the archive and builds it, while using local path uses a pre-built archive.
4039
4140
## Command line options
4241
4342
* `--sha512` - checks the archive matches the given SHA-512 checksum. Only
44-
applies to installations via URL or local path
43+
applies to installations via a local path
4544
4645
* `--force` - forces installation without a shell prompt; primarily
4746
intended for automation in build systems like Make
@@ -55,9 +54,6 @@ defmodule Mix.Tasks.Archive.Install do
5554
* `--organization` - specifies an organization to use if fetching the package
5655
from a private Hex repository
5756
58-
* `--timeout` - sets a request timeout in milliseconds for fetching
59-
archives from URLs. Default is 60 seconds
60-
6157
"""
6258

6359
@behaviour Mix.Local.Installer
@@ -77,17 +73,25 @@ defmodule Mix.Tasks.Archive.Install do
7773
end
7874

7975
@impl true
80-
def check_install_spec({local_or_url, path_or_url} = _install_spec, _opts)
81-
when local_or_url in [:local, :url] do
76+
def check_install_spec({:local, path} = _install_spec, _opts) do
77+
check_extname(path)
78+
end
79+
80+
def check_install_spec({:url, url} = _install_spec, _opts) do
81+
Mix.Utils.warn_install_over_http_deprecated("archive.install", url)
82+
check_extname(url)
83+
end
84+
85+
def check_install_spec(_, _), do: :ok
86+
87+
defp check_extname(path_or_url) do
8288
if Path.extname(path_or_url) == ".ez" do
8389
:ok
8490
else
85-
{:error, "Expected a local file path or a file URL ending in \".ez\"."}
91+
{:error, "Expected a local file path ending in \".ez\"."}
8692
end
8793
end
8894

89-
def check_install_spec(_, _), do: :ok
90-
9195
@impl true
9296
def find_previous_versions(src) do
9397
app =

lib/mix/lib/mix/tasks/escript.install.ex

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,11 @@ defmodule Mix.Tasks.Escript.Install do
1212
1313
mix do escript.build, escript.install
1414
15-
If an argument is provided, it should be a local path or a URL to a prebuilt escript,
15+
If an argument is provided, it should be a local path to a prebuilt escript,
1616
a Git repository, a GitHub repository, or a Hex package.
1717
1818
mix escript.install escript
1919
mix escript.install path/to/escript
20-
mix escript.install https://example.com/my_escript
2120
mix escript.install git https://path/to/git/repo
2221
mix escript.install git https://path/to/git/repo branch git_branch
2322
mix escript.install git https://path/to/git/repo tag git_tag
@@ -40,7 +39,7 @@ defmodule Mix.Tasks.Escript.Install do
4039
## Command line options
4140
4241
* `--sha512` - checks the escript matches the given SHA-512 checksum. Only
43-
applies to installations via URL or local path
42+
applies to installations via a local path
4443
4544
* `--force` - forces installation without a shell prompt; primarily
4645
intended for automation in build systems like Make
@@ -54,9 +53,6 @@ defmodule Mix.Tasks.Escript.Install do
5453
* `--organization` - specifies an organization to use if fetching the package
5554
from a private Hex repository
5655
57-
* `--timeout` - sets a request timeout in milliseconds for fetching
58-
archives from URLs. Default is 60 seconds
59-
6056
"""
6157

6258
@behaviour Mix.Local.Installer
@@ -79,6 +75,11 @@ defmodule Mix.Tasks.Escript.Install do
7975
end
8076

8177
@impl true
78+
def check_install_spec({:url, url} = _install_spec, _opts) do
79+
Mix.Utils.warn_install_over_http_deprecated("escript.install", url)
80+
:ok
81+
end
82+
8283
def check_install_spec(_, _), do: :ok
8384

8485
@impl true

lib/mix/lib/mix/tasks/local.rebar.ex

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ defmodule Mix.Tasks.Local.Rebar do
2525
2626
## Command line options
2727
28-
* `rebar PATH` - specifies a path or URL for `rebar`
28+
* `rebar PATH` - specifies a path for `rebar`
2929
30-
* `rebar3 PATH` - specifies a path or URL for `rebar3`
30+
* `rebar3 PATH` - specifies a path for `rebar3`
3131
3232
* `--sha512` - checks the archive matches the given SHA-512 checksum
3333
@@ -68,6 +68,8 @@ defmodule Mix.Tasks.Local.Rebar do
6868
defp install_from_path(manager, path, opts) do
6969
local = Mix.Rebar.local_rebar_path(manager)
7070

71+
if file_url?(path), do: warn_install_over_http_deprecated(manager, path)
72+
7173
if opts[:force] || Mix.Generator.overwrite?(local) do
7274
case Mix.Utils.read_path(path, opts) do
7375
{:ok, binary} ->
@@ -77,7 +79,7 @@ defmodule Mix.Tasks.Local.Rebar do
7779
Mix.shell().info([:green, "* creating ", :reset, Path.relative_to_cwd(local)])
7880

7981
:badpath ->
80-
Mix.raise("Expected #{inspect(path)} to be a URL or a local file path")
82+
Mix.raise("Expected #{inspect(path)} to be a local file path")
8183

8284
{:local, message} ->
8385
Mix.raise(message)
@@ -100,6 +102,10 @@ defmodule Mix.Tasks.Local.Rebar do
100102
true
101103
end
102104

105+
defp file_url?(url_or_path) do
106+
URI.parse(url_or_path).scheme in ["http", "https"]
107+
end
108+
103109
defp install_from_s3(manager, list_url, escript_url, opts) do
104110
hex_mirror = Mix.Hex.mirror()
105111
list_url = hex_mirror <> list_url
@@ -114,4 +120,37 @@ defmodule Mix.Tasks.Local.Rebar do
114120

115121
install_from_path(manager, url, Keyword.put(opts, :sha512, sha512))
116122
end
123+
124+
defp warn_install_over_http_deprecated(manager, url) do
125+
shell = Mix.shell()
126+
basename = Path.basename(url)
127+
128+
shell.error("""
129+
Warning: the use of HTTP/HTTPS URLs with `mix local.rebar` is deprecated")
130+
131+
Run `mix help local.rebar` for details on installing #{manager} from Hex's CDN.
132+
Alternatively you can fetch the file using an external HTTP client and then
133+
install it locally:
134+
135+
Unix (Linux, MacOS X):
136+
137+
$ wget #{url}
138+
$ mix local.rebar #{manager} #{basename}
139+
140+
or
141+
142+
$ curl -o #{basename} #{url}
143+
$ mix local.rebar #{manager} #{basename}
144+
145+
Windows (Win7 or later):
146+
147+
> powershell -Command "Invoke-WebRequest #{url} -OutFile #{basename}"
148+
> mix local.rebar #{manager} #{basename}
149+
150+
or
151+
152+
> powershell -Command "(New-Object Net.WebClient).DownloadFile('#{url}', '#{basename}')"
153+
> mix local.rebar #{manager} #{basename}
154+
""")
155+
end
117156
end

lib/mix/lib/mix/utils.ex

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -676,4 +676,38 @@ defmodule Mix.Utils do
676676

677677
[proxy_auth: {user, pass}]
678678
end
679+
680+
def warn_install_over_http_deprecated(task_name, url) do
681+
basename = Path.basename(url)
682+
683+
shell = Mix.shell()
684+
685+
shell.error("""
686+
Warning: the use of HTTP/HTTPS URLs with `mix #{task_name}` is deprecated
687+
688+
Run `mix help #{task_name}` for details on the available alternatives, using
689+
hex, git or github. Alternatively you can fetch the file using an external HTTP
690+
client and then install it locally:
691+
692+
Unix (Linux, MacOS X):
693+
694+
$ wget #{url}
695+
$ mix #{task_name} #{basename}
696+
697+
or
698+
699+
$ curl -o #{basename} #{url}
700+
$ mix #{task_name} #{basename}
701+
702+
Windows (Win7 or later):
703+
704+
> powershell -Command "Invoke-WebRequest #{url} -OutFile #{basename}"
705+
> mix #{task_name} #{basename}
706+
707+
or
708+
709+
> powershell -Command "(New-Object Net.WebClient).DownloadFile('#{url}', '#{basename}')"
710+
> mix #{task_name} #{basename}
711+
""")
712+
end
679713
end

lib/mix/test/mix/tasks/archive_test.exs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ defmodule Mix.Tasks.ArchiveTest do
8282
# Try to override it with URL
8383
send(self(), {:mix_shell_input, :yes?, false})
8484
Mix.Tasks.Archive.Install.run(["https://example.com/archive-0.1.0?hello.ez"])
85+
86+
assert_received {:mix_shell, :error, ["Warning: the use of HTTP/HTTPS URLs" <> _]}
8587
assert_received {:mix_shell, :yes?, ["Found existing entry: " <> _]}
8688

8789
# Loading the archive should emit warning again
@@ -116,7 +118,7 @@ defmodule Mix.Tasks.ArchiveTest do
116118
end
117119

118120
test "archive install missing file" do
119-
message = ~r[Expected "./unlikely-to-exist-0.1.0.ez" to be a URL or a local file path]
121+
message = ~r[Expected "./unlikely-to-exist-0.1.0.ez" to be a local file path]
120122

121123
assert_raise Mix.Error, message, fn ->
122124
Mix.Tasks.Archive.Install.run(["./unlikely-to-exist-0.1.0.ez"])

lib/mix/test/mix/tasks/escript_test.exs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,13 @@ defmodule Mix.Tasks.EscriptTest do
242242
assert_received {:mix_shell, :info, ["* escript_test"]}
243243
refute_received {:mix_shell, :info, ["* escript_test.bat"]}
244244

245+
# Try to override it with URL
246+
send(self(), {:mix_shell_input, :yes?, false})
247+
Mix.Tasks.Escript.Install.run(["https://example.com/escript_test"])
248+
249+
assert_received {:mix_shell, :error, ["Warning: the use of HTTP/HTTPS URLs" <> _]}
250+
assert_received {:mix_shell, :yes?, ["Found existing entry: " <> _]}
251+
245252
# check uninstall confirmation
246253
send(self(), {:mix_shell_input, :yes?, false})
247254
Mix.Tasks.Escript.Uninstall.run(["escript_test"])

0 commit comments

Comments
 (0)