Repository: derekkraan/curl_req (elixir)

Issue:
Support insecure connection / `-k` Flag
We would need to pass down options to `finch`/`mint` to skip SSL verification.

This could be set in req like

```elixir
Req.get!(url, connect_options: [transport_opts: [verify: :verify_none]])
```

For more information see: https://hexdocs.pm/req/0.5.8/Req.Steps.html#run_finch/1


> ` -k, --insecure      Allow insecure server connections when using SSL`

Pull request description:
Add insecure flag
Closes #22 

I added the new insecure flag and updated the Changelog and mix version to prepare for a new release ;)

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8f30fb6..31981c1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,7 @@
 - Switch some flag positions in the generated cURL command
 - Some bugfixes regarding the constructed Req.Request struct when multiple request steps have to be set
 - [BREAKING]: From cURL to Req the body gets encoded in the specified encoding and set in the correct Req option
+- New `CurlReq.Request` module for an internal representation
 
 ## 0.99.0
 
diff --git a/lib/curl_req/curl.ex b/lib/curl_req/curl.ex
index 065be7b..c1eb218 100644
--- a/lib/curl_req/curl.ex
+++ b/lib/curl_req/curl.ex
@@ -33,7 +33,8 @@ defmodule CurlReq.Curl do
           proxy: :string,
           proxy_user: :string,
           netrc: :boolean,
-          netrc_file: :string
+          netrc_file: :string,
+          insecure: :boolean
         ],
         aliases: [
           H: :header,
@@ -46,7 +47,8 @@ defmodule CurlReq.Curl do
           u: :user,
           x: :proxy,
           U: :proxy_user,
-          n: :netrc
+          n: :netrc,
+          k: :insecure
         ]
       )
 
@@ -85,6 +87,7 @@ defmodule CurlReq.Curl do
     |> add_auth(options)
     |> add_compression(options)
     |> add_proxy(options)
+    |> add_insecure(options)
     |> configure_redirects(options)
   end
 
@@ -201,6 +204,10 @@ defmodule CurlReq.Curl do
     end
   end
 
+  defp add_insecure(request, options) do
+    CurlReq.Request.put_insecure(request, options[:insecure])
+  end
+
   defp configure_redirects(request, options) do
     CurlReq.Request.put_redirect(request, options[:location])
   end
@@ -310,11 +317,14 @@ defmodule CurlReq.Curl do
         _ -> []
       end
 
+    insecure = if request.insecure, do: [insecure_flag(flag_style)], else: []
+
     url = [" ", to_string(request.url)]
 
     IO.iodata_to_binary([
       "curl",
       compressed,
+      insecure,
       auth,
       headers,
       cookies,
@@ -376,4 +386,7 @@ defmodule CurlReq.Curl do
 
   defp proxy_user_flag(:short, value), do: [" -U ", escape(value)]
   defp proxy_user_flag(:long, value), do: [" --proxy-user ", escape(value)]
+
+  defp insecure_flag(:short), do: " -k"
+  defp insecure_flag(:long), do: " --insecure"
 end
diff --git a/lib/curl_req/req.ex b/lib/curl_req/req.ex
index 90c598c..415d1e0 100644
--- a/lib/curl_req/req.ex
+++ b/lib/curl_req/req.ex
@@ -37,6 +37,14 @@ defmodule CurlReq.Req do
                 nil
             end
 
+          request =
+            with transport_opts <- Keyword.get(connect_options, :transport_opts, []),
+                 :verify_none <- Keyword.get(transport_opts, :verify) do
+              CurlReq.Request.put_insecure(request, true)
+            else
+              _ -> request
+            end
+
           case Keyword.get(connect_options, :proxy) do
             {scheme, host, port, _} ->
               CurlReq.Request.put_proxy(request, %URI{
@@ -146,31 +154,45 @@ defmodule CurlReq.Req do
         req
       end
 
-    req =
+    proxy =
       if request.proxy do
         %URI{scheme: scheme, host: host, port: port} = request.proxy_url
 
-        connect_options =
+        [
+          proxy: {String.to_existing_atom(scheme), host, port, []}
+        ]
+      else
+        []
+      end
+
+    proxy_auth =
+      case request.proxy_auth do
+        {:basic, userinfo} ->
           [
-            proxy: {String.to_existing_atom(scheme), host, port, []}
+            proxy_headers: [
+              {"proxy-authorization", "Basic " <> Base.encode64(userinfo)}
+            ]
           ]
 
-        connect_options =
-          case request.proxy_auth do
-            :none ->
-              connect_options
+        _ ->
+          []
+      end
 
-            {:basic, userinfo} ->
-              Keyword.merge(connect_options,
-                proxy_headers: [
-                  {"proxy-authorization", "Basic " <> Base.encode64(userinfo)}
-                ]
-              )
+    transport_opts =
+      if request.insecure do
+        [transport_opts: [verify: :verify_none]]
+      else
+        []
+      end
 
-            _ ->
-              connect_options
-          end
+    connect_options =
+      []
+      |> Keyword.merge(proxy)
+      |> Keyword.merge(proxy_auth)
+      |> Keyword.merge(transport_opts)
 
+    req =
+      if connect_options != [] do
         req
         |> Req.Request.register_options([
           :connect_options
diff --git a/lib/curl_req/request.ex b/lib/curl_req/request.ex
index 68b7e6b..57e3e96 100644
--- a/lib/curl_req/request.ex
+++ b/lib/curl_req/request.ex
@@ -23,7 +23,8 @@ defmodule CurlReq.Request do
           auth: auth(),
           encoding: encoding(),
           body: term(),
-          raw_body: term()
+          raw_body: term(),
+          insecure: boolean()
         }
 
   @type user_agent() :: :curl | :req | String.t()
@@ -49,7 +50,8 @@ defmodule CurlReq.Request do
             auth: :none,
             encoding: :raw,
             body: nil,
-            raw_body: nil
+            raw_body: nil,
+            insecure: false
 
   @doc """
   Puts the header into the CurlReq.Request struct. Special headers like encoding, authorization or user-agent are stored in their respective field in the #{__MODULE__} struct instead of a general header.
@@ -369,6 +371,22 @@ defmodule CurlReq.Request do
     %{request | compression: type}
   end
 
+  @doc """
+  Sets the insecure option in the Curl.Request struct
+
+  ## Examples
+
+      iex> request = %CurlReq.Request{} |> CurlReq.Request.put_insecure(true)
+      iex> request.insecure
+      true
+  """
+  @spec put_insecure(__MODULE__.t(), boolean() | nil) :: __MODULE__.t()
+  def put_insecure(%__MODULE__{} = request, nil), do: request
+
+  def put_insecure(%__MODULE__{} = request, insecure) when is_boolean(insecure) do
+    %{request | insecure: insecure}
+  end
+
   @doc """
   Sets the redirect option in the Curl.Request struct
 
diff --git a/mix.exs b/mix.exs
index a7db916..f00531e 100644
--- a/mix.exs
+++ b/mix.exs
@@ -11,7 +11,7 @@ defmodule CurlReq.MixProject do
       package: package(),
       source_url: "https://github.com/derekkraan/curl_req",
       start_permanent: Mix.env() == :prod,
-      version: "0.99.0"
+      version: "0.100.0"
     ]
   end
 


Test patch:
diff --git a/test/curl_req_test.exs b/test/curl_req_test.exs
index f2612f2..d281488 100644
--- a/test/curl_req_test.exs
+++ b/test/curl_req_test.exs
@@ -168,6 +168,35 @@ defmodule CurlReqTest do
                Req.new(url: "https://example.com", json: %{key: "val"})
                |> CurlReq.to_curl(run_steps: [except: [:compressed, :encode_body]])
     end
+
+    test "insecure flag" do
+      assert ~s(curl -k -X GET http://example.com) ==
+               %Req.Request{
+                 url: URI.parse("http://example.com"),
+                 registered_options: MapSet.new([:connect_options]),
+                 options: %{
+                   connect_options: [
+                     transport_opts: [verify: :verify_none]
+                   ]
+                 }
+               }
+               |> CurlReq.to_curl()
+    end
+
+    test "insecure flag with proxy" do
+      assert ~s(curl -k -x "http://my.proxy.com:2233" -X GET http://example.com) ==
+               %Req.Request{
+                 url: URI.parse("http://example.com"),
+                 registered_options: MapSet.new([:connect_options]),
+                 options: %{
+                   connect_options: [
+                     proxy: {:http, "my.proxy.com", 2233, []},
+                     transport_opts: [verify: :verify_none]
+                   ]
+                 }
+               }
+               |> CurlReq.to_curl()
+    end
   end
 
   describe "from_curl" do
@@ -448,6 +477,44 @@ defmodule CurlReqTest do
         end
       )
     end
+
+    test "insecure flag" do
+      assert ~CURL(curl -k http://example.com) ==
+               %Req.Request{
+                 url: URI.parse("http://example.com"),
+                 registered_options: MapSet.new([:connect_options]),
+                 options: %{
+                   connect_options: [
+                     transport_opts: [verify: :verify_none]
+                   ]
+                 }
+               }
+
+      assert ~CURL(curl --insecure http://example.com) ==
+               %Req.Request{
+                 url: URI.parse("http://example.com"),
+                 registered_options: MapSet.new([:connect_options]),
+                 options: %{
+                   connect_options: [
+                     transport_opts: [verify: :verify_none]
+                   ]
+                 }
+               }
+    end
+
+    test "insecure flag with proxy" do
+      assert ~CURL(curl -k --proxy my.proxy.com:2233 http://example.com) ==
+               %Req.Request{
+                 url: URI.parse("http://example.com"),
+                 registered_options: MapSet.new([:connect_options]),
+                 options: %{
+                   connect_options: [
+                     proxy: {:http, "my.proxy.com", 2233, []},
+                     transport_opts: [verify: :verify_none]
+                   ]
+                 }
+               }
+    end
   end
 
   describe "newlines" do