dependabot-hex 0.118.16 → 0.119.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,228 @@
1
+ defmodule Jason do
2
+ @moduledoc """
3
+ A blazing fast JSON parser and generator in pure Elixir.
4
+ """
5
+
6
+ alias Jason.{Encode, Decoder, DecodeError, EncodeError, Formatter}
7
+
8
+ @type escape :: :json | :unicode_safe | :html_safe | :javascript_safe
9
+ @type maps :: :naive | :strict
10
+
11
+ @type encode_opt :: {:escape, escape} | {:maps, maps} | {:pretty, boolean | Formatter.opts()}
12
+
13
+ @type keys :: :atoms | :atoms! | :strings | :copy | (String.t() -> term)
14
+
15
+ @type strings :: :reference | :copy
16
+
17
+ @type decode_opt :: {:keys, keys} | {:strings, strings}
18
+
19
+ @doc """
20
+ Parses a JSON value from `input` iodata.
21
+
22
+ ## Options
23
+
24
+ * `:keys` - controls how keys in objects are decoded. Possible values are:
25
+
26
+ * `:strings` (default) - decodes keys as binary strings,
27
+ * `:atoms` - keys are converted to atoms using `String.to_atom/1`,
28
+ * `:atoms!` - keys are converted to atoms using `String.to_existing_atom/1`,
29
+ * custom decoder - additionally a function accepting a string and returning a key
30
+ is accepted.
31
+
32
+ * `:strings` - controls how strings (including keys) are decoded. Possible values are:
33
+
34
+ * `:reference` (default) - when possible tries to create a sub-binary into the original
35
+ * `:copy` - always copies the strings. This option is especially useful when parts of the
36
+ decoded data will be stored for a long time (in ets or some process) to avoid keeping
37
+ the reference to the original data.
38
+
39
+ ## Decoding keys to atoms
40
+
41
+ The `:atoms` option uses the `String.to_atom/1` call that can create atoms at runtime.
42
+ Since the atoms are not garbage collected, this can pose a DoS attack vector when used
43
+ on user-controlled data.
44
+
45
+ ## Examples
46
+
47
+ iex> Jason.decode("{}")
48
+ {:ok, %{}}
49
+
50
+ iex> Jason.decode("invalid")
51
+ {:error, %Jason.DecodeError{data: "invalid", position: 0, token: nil}}
52
+ """
53
+ @spec decode(iodata, [decode_opt]) :: {:ok, term} | {:error, DecodeError.t()}
54
+ def decode(input, opts \\ []) do
55
+ input = IO.iodata_to_binary(input)
56
+ Decoder.parse(input, format_decode_opts(opts))
57
+ end
58
+
59
+ @doc """
60
+ Parses a JSON value from `input` iodata.
61
+
62
+ Similar to `decode/2` except it will unwrap the error tuple and raise
63
+ in case of errors.
64
+
65
+ ## Examples
66
+
67
+ iex> Jason.decode!("{}")
68
+ %{}
69
+
70
+ iex> Jason.decode!("invalid")
71
+ ** (Jason.DecodeError) unexpected byte at position 0: 0x69 ('i')
72
+
73
+ """
74
+ @spec decode!(iodata, [decode_opt]) :: term | no_return
75
+ def decode!(input, opts \\ []) do
76
+ case decode(input, opts) do
77
+ {:ok, result} -> result
78
+ {:error, error} -> raise error
79
+ end
80
+ end
81
+
82
+ @doc """
83
+ Generates JSON corresponding to `input`.
84
+
85
+ The generation is controlled by the `Jason.Encoder` protocol,
86
+ please refer to the module to read more on how to define the protocol
87
+ for custom data types.
88
+
89
+ ## Options
90
+
91
+ * `:escape` - controls how strings are encoded. Possible values are:
92
+
93
+ * `:json` (default) - the regular JSON escaping as defined by RFC 7159.
94
+ * `:javascript_safe` - additionally escapes the LINE SEPARATOR (U+2028)
95
+ and PARAGRAPH SEPARATOR (U+2029) characters to make the produced JSON
96
+ valid JavaScript.
97
+ * `:html_safe` - similar to `:javascript_safe`, but also escapes the `/`
98
+ character to prevent XSS.
99
+ * `:unicode_safe` - escapes all non-ascii characters.
100
+
101
+ * `:maps` - controls how maps are encoded. Possible values are:
102
+
103
+ * `:strict` - checks the encoded map for duplicate keys and raises
104
+ if they appear. For example `%{:foo => 1, "foo" => 2}` would be
105
+ rejected, since both keys would be encoded to the string `"foo"`.
106
+ * `:naive` (default) - does not perform the check.
107
+
108
+ * `:pretty` - controls pretty printing of the output. Possible values are:
109
+
110
+ * `true` to pretty print with default configuration
111
+ * a keyword of options as specified by `Jason.Formatter.pretty_print/2`.
112
+
113
+ ## Examples
114
+
115
+ iex> Jason.encode(%{a: 1})
116
+ {:ok, ~S|{"a":1}|}
117
+
118
+ iex> Jason.encode("\\xFF")
119
+ {:error, %Jason.EncodeError{message: "invalid byte 0xFF in <<255>>"}}
120
+
121
+ """
122
+ @spec encode(term, [encode_opt]) ::
123
+ {:ok, String.t()} | {:error, EncodeError.t() | Exception.t()}
124
+ def encode(input, opts \\ []) do
125
+ case do_encode(input, format_encode_opts(opts)) do
126
+ {:ok, result} -> {:ok, IO.iodata_to_binary(result)}
127
+ {:error, error} -> {:error, error}
128
+ end
129
+ end
130
+
131
+ @doc """
132
+ Generates JSON corresponding to `input`.
133
+
134
+ Similar to `encode/1` except it will unwrap the error tuple and raise
135
+ in case of errors.
136
+
137
+ ## Examples
138
+
139
+ iex> Jason.encode!(%{a: 1})
140
+ ~S|{"a":1}|
141
+
142
+ iex> Jason.encode!("\\xFF")
143
+ ** (Jason.EncodeError) invalid byte 0xFF in <<255>>
144
+
145
+ """
146
+ @spec encode!(term, [encode_opt]) :: String.t() | no_return
147
+ def encode!(input, opts \\ []) do
148
+ case do_encode(input, format_encode_opts(opts)) do
149
+ {:ok, result} -> IO.iodata_to_binary(result)
150
+ {:error, error} -> raise error
151
+ end
152
+ end
153
+
154
+ @doc """
155
+ Generates JSON corresponding to `input` and returns iodata.
156
+
157
+ This function should be preferred to `encode/2`, if the generated
158
+ JSON will be handed over to one of the IO functions or sent
159
+ over the socket. The Erlang runtime is able to leverage vectorised
160
+ writes and avoid allocating a continuous buffer for the whole
161
+ resulting string, lowering memory use and increasing performance.
162
+
163
+ ## Examples
164
+
165
+ iex> {:ok, iodata} = Jason.encode_to_iodata(%{a: 1})
166
+ iex> IO.iodata_to_binary(iodata)
167
+ ~S|{"a":1}|
168
+
169
+ iex> Jason.encode_to_iodata("\\xFF")
170
+ {:error, %Jason.EncodeError{message: "invalid byte 0xFF in <<255>>"}}
171
+
172
+ """
173
+ @spec encode_to_iodata(term, [encode_opt]) ::
174
+ {:ok, iodata} | {:error, EncodeError.t() | Exception.t()}
175
+ def encode_to_iodata(input, opts \\ []) do
176
+ do_encode(input, format_encode_opts(opts))
177
+ end
178
+
179
+ @doc """
180
+ Generates JSON corresponding to `input` and returns iodata.
181
+
182
+ Similar to `encode_to_iodata/1` except it will unwrap the error tuple
183
+ and raise in case of errors.
184
+
185
+ ## Examples
186
+
187
+ iex> iodata = Jason.encode_to_iodata!(%{a: 1})
188
+ iex> IO.iodata_to_binary(iodata)
189
+ ~S|{"a":1}|
190
+
191
+ iex> Jason.encode_to_iodata!("\\xFF")
192
+ ** (Jason.EncodeError) invalid byte 0xFF in <<255>>
193
+
194
+ """
195
+ @spec encode_to_iodata!(term, [encode_opt]) :: iodata | no_return
196
+ def encode_to_iodata!(input, opts \\ []) do
197
+ case do_encode(input, format_encode_opts(opts)) do
198
+ {:ok, result} -> result
199
+ {:error, error} -> raise error
200
+ end
201
+ end
202
+
203
+ defp do_encode(input, %{pretty: true} = opts) do
204
+ case Encode.encode(input, opts) do
205
+ {:ok, encoded} -> {:ok, Formatter.pretty_print_to_iodata(encoded)}
206
+ other -> other
207
+ end
208
+ end
209
+
210
+ defp do_encode(input, %{pretty: pretty} = opts) when pretty !== false do
211
+ case Encode.encode(input, opts) do
212
+ {:ok, encoded} -> {:ok, Formatter.pretty_print_to_iodata(encoded, pretty)}
213
+ other -> other
214
+ end
215
+ end
216
+
217
+ defp do_encode(input, opts) do
218
+ Encode.encode(input, opts)
219
+ end
220
+
221
+ defp format_encode_opts(opts) do
222
+ Enum.into(opts, %{escape: :json, maps: :naive})
223
+ end
224
+
225
+ defp format_decode_opts(opts) do
226
+ Enum.into(opts, %{keys: :strings, strings: :reference})
227
+ end
228
+ end
@@ -0,0 +1,76 @@
1
+ defmodule Jason.Mixfile do
2
+ use Mix.Project
3
+
4
+ @version "1.2.1"
5
+
6
+ def project() do
7
+ [
8
+ app: :jason,
9
+ version: @version,
10
+ elixir: "~> 1.4",
11
+ start_permanent: Mix.env() == :prod,
12
+ consolidate_protocols: Mix.env() != :test,
13
+ deps: deps(),
14
+ preferred_cli_env: [docs: :docs],
15
+ dialyzer: dialyzer(),
16
+ description: description(),
17
+ package: package(),
18
+ docs: docs()
19
+ ]
20
+ end
21
+
22
+ def application() do
23
+ [
24
+ extra_applications: []
25
+ ]
26
+ end
27
+
28
+ defp deps() do
29
+ [
30
+ {:decimal, "~> 1.0", optional: true},
31
+ {:dialyxir, "~> 1.0", only: [:dev, :test], runtime: false},
32
+ {:ex_doc, "~> 0.18", only: :docs},
33
+ ] ++ maybe_stream_data()
34
+ end
35
+
36
+ defp maybe_stream_data() do
37
+ if Version.match?(System.version(), "~> 1.5") do
38
+ [{:stream_data, "~> 0.4", only: :test}]
39
+ else
40
+ []
41
+ end
42
+ end
43
+
44
+ defp dialyzer() do
45
+ [
46
+ ignore_warnings: "dialyzer.ignore"
47
+ ]
48
+ end
49
+
50
+ defp description() do
51
+ """
52
+ A blazing fast JSON parser and generator in pure Elixir.
53
+ """
54
+ end
55
+
56
+ defp package() do
57
+ [
58
+ maintainers: ["Michał Muskała"],
59
+ licenses: ["Apache-2.0"],
60
+ links: %{"GitHub" => "https://github.com/michalmuskala/jason"}
61
+ ]
62
+ end
63
+
64
+ defp docs() do
65
+ [
66
+ main: "readme",
67
+ name: "Jason",
68
+ source_ref: "v#{@version}",
69
+ canonical: "http://hexdocs.pm/jason",
70
+ source_url: "https://github.com/michalmuskala/jason",
71
+ extras: [
72
+ "README.md"
73
+ ]
74
+ ]
75
+ end
76
+ end
@@ -0,0 +1,92 @@
1
+ defmodule UpdateChecker do
2
+ def run(dependency_name, credentials) do
3
+ set_credentials(credentials)
4
+
5
+ # Update the lockfile in a session that we can time out
6
+ task = Task.async(fn -> do_resolution(dependency_name) end)
7
+ case Task.yield(task, 30000) || Task.shutdown(task) do
8
+ {:ok, {:ok, :resolution_successful}} ->
9
+ # Read the new lock
10
+ {updated_lock, _updated_rest_lock} =
11
+ Map.split(Mix.Dep.Lock.read(), [String.to_atom(dependency_name)])
12
+
13
+ # Get the new dependency version
14
+ version =
15
+ updated_lock
16
+ |> Map.get(String.to_atom(dependency_name))
17
+ |> elem(2)
18
+ {:ok, version}
19
+
20
+ {:ok, {:error, error}} -> {:error, error}
21
+
22
+ nil -> {:error, :dependency_resolution_timed_out}
23
+
24
+ {:exit, reason} -> {:error, reason}
25
+ end
26
+ end
27
+
28
+ defp set_credentials(credentials) do
29
+ credentials
30
+ |> Enum.reduce([], fn cred, acc ->
31
+ if List.last(acc) == nil || List.last(acc)[:token] do
32
+ List.insert_at(acc, -1, %{organization: cred})
33
+ else
34
+ {item, acc} = List.pop_at(acc, -1)
35
+ item = Map.put(item, :token, cred)
36
+ List.insert_at(acc, -1, item)
37
+ end
38
+ end)
39
+ |> Enum.each(fn cred ->
40
+ hexpm = Hex.Repo.get_repo("hexpm")
41
+
42
+ repo = %{
43
+ url: hexpm.url <> "/repos/#{cred.organization}",
44
+ public_key: nil,
45
+ auth_key: cred.token
46
+ }
47
+
48
+ Hex.Config.read()
49
+ |> Hex.Config.read_repos()
50
+ |> Map.put("hexpm:#{cred.organization}", repo)
51
+ |> Hex.Config.update_repos()
52
+ end)
53
+ end
54
+
55
+ defp do_resolution(dependency_name) do
56
+ # Fetch dependencies that needs updating
57
+ {dependency_lock, rest_lock} =
58
+ Map.split(Mix.Dep.Lock.read(), [String.to_atom(dependency_name)])
59
+
60
+ try do
61
+ Mix.Dep.Fetcher.by_name([dependency_name], dependency_lock, rest_lock, [])
62
+ {:ok, :resolution_successful}
63
+ rescue
64
+ error -> {:error, error}
65
+ end
66
+ end
67
+ end
68
+
69
+ [dependency_name | credentials] = System.argv()
70
+
71
+
72
+ case UpdateChecker.run(dependency_name, credentials) do
73
+ {:ok, version} ->
74
+ version = :erlang.term_to_binary({:ok, version})
75
+ IO.write(:stdio, version)
76
+
77
+ {:error, %Hex.Version.InvalidRequirementError{} = error} ->
78
+ result = :erlang.term_to_binary({:error, "Invalid requirement: #{error.requirement}"})
79
+ IO.write(:stdio, result)
80
+
81
+ {:error, %Mix.Error{} = error} ->
82
+ result = :erlang.term_to_binary({:error, "Dependency resolution failed: #{error.message}"})
83
+ IO.write(:stdio, result)
84
+
85
+ {:error, :dependency_resolution_timed_out} ->
86
+ # We do nothing here because Hex is already printing out a message in stdout
87
+ nil
88
+
89
+ {:error, error} ->
90
+ result = :erlang.term_to_binary({:error, "Unknown error in check_update: #{inspect(error)}"})
91
+ IO.write(:stdio, result)
92
+ end
@@ -0,0 +1,39 @@
1
+ [dependency_name | credentials] = System.argv()
2
+
3
+ grouped_creds = Enum.reduce credentials, [], fn cred, acc ->
4
+ if List.last(acc) == nil || List.last(acc)[:token] do
5
+ List.insert_at(acc, -1, %{ organization: cred })
6
+ else
7
+ { item, acc } = List.pop_at(acc, -1)
8
+ item = Map.put(item, :token, cred)
9
+ List.insert_at(acc, -1, item)
10
+ end
11
+ end
12
+
13
+ Enum.each grouped_creds, fn cred ->
14
+ hexpm = Hex.Repo.get_repo("hexpm")
15
+ repo = %{
16
+ url: hexpm.url <> "/repos/#{cred.organization}",
17
+ public_key: nil,
18
+ auth_key: cred.token
19
+ }
20
+
21
+ Hex.Config.read()
22
+ |> Hex.Config.read_repos()
23
+ |> Map.put("hexpm:#{cred.organization}", repo)
24
+ |> Hex.Config.update_repos()
25
+ end
26
+
27
+ # dependency atom
28
+ dependency = String.to_atom(dependency_name)
29
+
30
+ # Fetch dependencies that needs updating
31
+ {dependency_lock, rest_lock} = Map.split(Mix.Dep.Lock.read(), [dependency])
32
+ Mix.Dep.Fetcher.by_name([dependency_name], dependency_lock, rest_lock, [])
33
+
34
+ lockfile_content =
35
+ "mix.lock"
36
+ |> File.read()
37
+ |> :erlang.term_to_binary()
38
+
39
+ IO.write(:stdio, lockfile_content)
@@ -0,0 +1,104 @@
1
+ defmodule Parser do
2
+ def run do
3
+ Mix.Dep.load_on_environment([])
4
+ |> Enum.flat_map(&parse_dep/1)
5
+ |> Enum.map(&build_dependency(&1.opts[:lock], &1))
6
+ end
7
+
8
+ defp build_dependency(nil, dep) do
9
+ %{
10
+ name: dep.app,
11
+ from: Path.relative_to_cwd(dep.from),
12
+ groups: [],
13
+ requirement: normalise_requirement(dep.requirement),
14
+ top_level: dep.top_level || umbrella_top_level_dep?(dep)
15
+ }
16
+ end
17
+
18
+ defp build_dependency(lock, dep) do
19
+ {version, checksum, source} = parse_lock(lock)
20
+ groups = parse_groups(dep.opts[:only])
21
+
22
+ %{
23
+ name: dep.app,
24
+ from: Path.relative_to_cwd(dep.from),
25
+ version: version,
26
+ groups: groups,
27
+ checksum: checksum,
28
+ requirement: normalise_requirement(dep.requirement),
29
+ source: source,
30
+ top_level: dep.top_level || umbrella_top_level_dep?(dep)
31
+ }
32
+ end
33
+
34
+ defp parse_groups(nil), do: []
35
+ defp parse_groups(only) when is_list(only), do: only
36
+ defp parse_groups(only), do: [only]
37
+
38
+ # path dependency
39
+ defp parse_dep(%{scm: Mix.SCM.Path, opts: opts} = dep) do
40
+ cond do
41
+ # umbrella dependency - ignore
42
+ opts[:in_umbrella] ->
43
+ []
44
+
45
+ # umbrella application
46
+ opts[:from_umbrella] ->
47
+ Enum.reject(dep.deps, fn dep -> dep.opts[:in_umbrella] end)
48
+
49
+ true ->
50
+ []
51
+ end
52
+ end
53
+
54
+ # hex, git dependency
55
+ defp parse_dep(%{scm: scm} = dep) when scm in [Hex.SCM, Mix.SCM.Git], do: [dep]
56
+
57
+ # unsupported
58
+ defp parse_dep(_dep), do: []
59
+
60
+ defp umbrella_top_level_dep?(dep) do
61
+ if Mix.Project.umbrella?() do
62
+ apps_paths = Path.expand(Mix.Project.config()[:apps_path], File.cwd!())
63
+ String.contains?(Path.dirname(Path.dirname(dep.from)), apps_paths)
64
+ else
65
+ false
66
+ end
67
+ end
68
+
69
+ defp parse_lock({:git, repo_url, checksum, opts}),
70
+ do: {nil, checksum, git_source(repo_url, opts)}
71
+
72
+ defp parse_lock(tuple) when elem(tuple, 0) == :hex do
73
+ destructure [:hex, _app, version, _old_checksum, _managers, _deps, _repo, checksum],
74
+ Tuple.to_list(tuple)
75
+
76
+ {version, checksum, nil}
77
+ end
78
+
79
+ defp normalise_requirement(req) do
80
+ req
81
+ |> maybe_regex_to_str()
82
+ |> empty_str_to_nil()
83
+ end
84
+
85
+ defp maybe_regex_to_str(s), do: if Regex.regex?(s), do: Regex.source(s), else: s
86
+ defp empty_str_to_nil(""), do: nil
87
+ defp empty_str_to_nil(s), do: s
88
+
89
+ def git_source(repo_url, opts) do
90
+ ref = opts[:ref] || opts[:tag]
91
+ ref = if is_list(ref), do: to_string(ref), else: ref
92
+
93
+ %{
94
+ type: "git",
95
+ url: repo_url,
96
+ branch: opts[:branch] || "master",
97
+ ref: ref
98
+ }
99
+ end
100
+ end
101
+
102
+ dependencies = :erlang.term_to_binary({:ok, Parser.run()})
103
+
104
+ IO.write(:stdio, dependencies)
@@ -0,0 +1,76 @@
1
+ defmodule DependencyHelper do
2
+ def main() do
3
+ IO.read(:stdio, :all)
4
+ |> Jason.decode!()
5
+ |> run()
6
+ |> case do
7
+ {output, 0} ->
8
+ if output =~ "No authenticated organization found" do
9
+ {:error, output}
10
+ else
11
+ {:ok, :erlang.binary_to_term(output)}
12
+ end
13
+
14
+ {error, 1} -> {:error, error}
15
+ end
16
+ |> handle_result()
17
+ end
18
+
19
+ defp handle_result({:ok, {:ok, result}}) do
20
+ encode_and_write(%{"result" => result})
21
+ end
22
+
23
+ defp handle_result({:ok, {:error, reason}}) do
24
+ encode_and_write(%{"error" => reason})
25
+ System.halt(1)
26
+ end
27
+
28
+ defp handle_result({:error, reason}) do
29
+ encode_and_write(%{"error" => reason})
30
+ System.halt(1)
31
+ end
32
+
33
+ defp encode_and_write(content) do
34
+ content
35
+ |> Jason.encode!()
36
+ |> IO.write()
37
+ end
38
+
39
+ defp run(%{"function" => "parse", "args" => [dir]}) do
40
+ run_script("parse_deps.exs", dir)
41
+ end
42
+
43
+ defp run(%{"function" => "get_latest_resolvable_version", "args" => [dir, dependency_name, credentials]}) do
44
+ run_script("check_update.exs", dir, [dependency_name] ++ credentials)
45
+ end
46
+
47
+ defp run(%{"function" => "get_updated_lockfile", "args" => [dir, dependency_name, credentials]}) do
48
+ run_script("do_update.exs", dir, [dependency_name] ++ credentials)
49
+ end
50
+
51
+ defp run_script(script, dir, args \\ []) do
52
+ args = [
53
+ "run",
54
+ "--no-deps-check",
55
+ "--no-start",
56
+ "--no-compile",
57
+ "--no-elixir-version-check",
58
+ script
59
+ ] ++ args
60
+
61
+ System.cmd(
62
+ "mix",
63
+ args,
64
+ [
65
+ cd: dir,
66
+ env: %{
67
+ "MIX_EXS" => nil,
68
+ "MIX_LOCK" => nil,
69
+ "MIX_DEPS" => nil
70
+ }
71
+ ]
72
+ )
73
+ end
74
+ end
75
+
76
+ DependencyHelper.main()
@@ -0,0 +1,21 @@
1
+ defmodule DependabotCore.Mixfile do
2
+ use Mix.Project
3
+
4
+ def project do
5
+ [app: :dependabot_core,
6
+ version: "0.1.0",
7
+ elixir: "~> 1.5",
8
+ start_permanent: Mix.env == :prod,
9
+ lockfile: System.get_env("MIX_LOCK") || "mix.lock",
10
+ deps_path: System.get_env("MIX_DEPS") || "deps",
11
+ deps: deps()]
12
+ end
13
+
14
+ def application do
15
+ [extra_applications: [:logger]]
16
+ end
17
+
18
+ defp deps() do
19
+ [{:jason, "~> 1.0"}]
20
+ end
21
+ end
@@ -0,0 +1,3 @@
1
+ %{
2
+ "jason": {:hex, :jason, "1.2.1", "12b22825e22f468c02eb3e4b9985f3d0cb8dc40b9bd704730efa11abd2708c44", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "b659b8571deedf60f79c5a608e15414085fa141344e2716fbd6988a084b5f993"},
3
+ }