Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix validation when opening notebook from file:// URL #2783

Merged
merged 1 commit into from
Sep 16, 2024
Merged
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
36 changes: 29 additions & 7 deletions lib/livebook/utils.ex
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,11 @@ defmodule Livebook.Utils do
@doc """
Validates if the given URL is syntactically valid.

## Options

* `:allow_file_scheme` - also accepts `file://` URLs. Defaults to
`flase`

## Examples

iex> Livebook.Utils.valid_url?("not_a_url")
Expand All @@ -221,22 +226,39 @@ defmodule Livebook.Utils do
iex> Livebook.Utils.valid_url?("http://")
false

iex> Livebook.Utils.valid_url?("file:///tmp/test")
false

iex> Livebook.Utils.valid_url?("file:///tmp/test", allow_file_scheme: true)
true

"""
@spec valid_url?(String.t()) :: boolean()
def valid_url?(url) do
@spec valid_url?(String.t(), keyword()) :: boolean()
def valid_url?(url, opts \\ []) do
opts = Keyword.validate!(opts, allow_file_scheme: false)
allow_file_scheme = opts[:allow_file_scheme]

case URI.new(url) do
{:ok, uri} -> uri.scheme != nil and uri.host not in [nil, ""]
{:error, _} -> false
{:ok, uri} when uri.scheme in ["http", "https"] ->
uri.host not in [nil, ""]

{:ok, uri} when allow_file_scheme and uri.scheme == "file" ->
String.starts_with?(url, "file://") and uri.path not in [nil, ""]

_ ->
false
end
end

@doc """
Validates a change is a valid URL.

See `valid_url?/2` for valid options.
"""
@spec validate_url(Ecto.Changeset.t(), atom()) :: Ecto.Changeset.t()
def validate_url(changeset, field) do
@spec validate_url(Ecto.Changeset.t(), atom(), keyword()) :: Ecto.Changeset.t()
def validate_url(changeset, field, opts \\ []) do
Ecto.Changeset.validate_change(changeset, field, fn ^field, url ->
if valid_url?(url) do
if valid_url?(url, opts) do
[]
else
[{field, "must be a valid URL"}]
Expand Down
2 changes: 1 addition & 1 deletion lib/livebook_web/live/open_live/url_component.ex
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ defmodule LivebookWeb.OpenLive.UrlComponent do

cast({data, types}, attrs, [:url])
|> validate_required([:url])
|> Livebook.Utils.validate_url(:url)
|> Livebook.Utils.validate_url(:url, allow_file_scheme: true)
|> Livebook.Utils.validate_not_s3_url(
:url,
~s{invalid s3:// URL scheme, you must first connect to the Cloud Storage in your Workspace page and then choose the relevant file in "From storage"}
Expand Down
Loading