aboutsummaryrefslogtreecommitdiff
path: root/lib/recaptcha
diff options
context:
space:
mode:
Diffstat (limited to 'lib/recaptcha')
-rw-r--r--lib/recaptcha/http.ex37
-rw-r--r--lib/recaptcha/http/mock_http_client.ex18
-rw-r--r--lib/recaptcha/response.ex8
-rw-r--r--lib/recaptcha/template.ex25
4 files changed, 88 insertions, 0 deletions
diff --git a/lib/recaptcha/http.ex b/lib/recaptcha/http.ex
new file mode 100644
index 0000000..01c088a
--- /dev/null
+++ b/lib/recaptcha/http.ex
@@ -0,0 +1,37 @@
+defmodule Recaptcha.Http do
+ @moduledoc """
+ Responsible for managing HTTP requests to the reCAPTCHA API
+ """
+ @headers [{"Content-type", "application/x-www-form-urlencoded"}, {"Accept", "application/json"}]
+ @url Application.get_env(:recaptcha, :verify_url)
+ @timeout Application.get_env(:recaptcha, :timeout, 5000)
+
+ @doc """
+ Sends an HTTP request to the reCAPTCHA version 2.0 API.
+
+ See the [documentation](https://developers.google.com/recaptcha/docs/verify#api-response) for more details on the API response.
+
+ ## Options
+
+ * `:timeout` - the timeout for the request (defaults to 5000ms)
+
+ ## Example
+
+ {:ok, %{ "success" => success, "challenge_ts" => ts, "hostname" => host, "error-codes" => errors}} = Recaptcha.Http.request_verification(%{ secret: "secret", response: "response", remote_ip: "remote_ip"})
+ """
+ @spec request_verification(map, [timeout: integer]) :: {:ok, map} | {:error, [atom]}
+ def request_verification(body, options \\ []) do
+ result =
+ with {:ok, response} <- HTTPoison.post(@url, body, @headers, timeout: options[:timeout] || @timeout),
+ {:ok, data} <- Poison.decode(response.body) do
+ {:ok, data}
+ end
+
+ case result do
+ {:ok, data} -> {:ok, data}
+ {:error, :invalid} -> {:error, [:invalid_api_response]}
+ {:error, {:invalid, _reason}} -> {:error, [:invalid_api_response]}
+ {:error, %{reason: reason}} -> {:error, [reason]}
+ end
+ end
+end
diff --git a/lib/recaptcha/http/mock_http_client.ex b/lib/recaptcha/http/mock_http_client.ex
new file mode 100644
index 0000000..2355dd3
--- /dev/null
+++ b/lib/recaptcha/http/mock_http_client.ex
@@ -0,0 +1,18 @@
+defmodule Recaptcha.Http.MockClient do
+ @moduledoc """
+ A mock HTTP client used for testing.
+ """
+
+ def request_verification(body, options \\ [])
+
+ def request_verification("response=valid_response&secret=6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe" = body, options) do
+ send self(), {:request_verification, body, options}
+ {:ok, %{"success" => true, "challenge_ts" => "timestamp", "hostname" => "localhost"}}
+ end
+
+ # every other match is a pass through to the real client
+ def request_verification(body, options) do
+ send self(), {:request_verification, body, options}
+ Recaptcha.Http.request_verification(body, options)
+ end
+end
diff --git a/lib/recaptcha/response.ex b/lib/recaptcha/response.ex
new file mode 100644
index 0000000..f8adb18
--- /dev/null
+++ b/lib/recaptcha/response.ex
@@ -0,0 +1,8 @@
+defmodule Recaptcha.Response do
+ @moduledoc """
+ A struct representing the successful recaptcha response from the reCAPTCHA API.
+ """
+ defstruct challenge_ts: "", hostname: ""
+
+ @type t :: %__MODULE__{challenge_ts: String.t, hostname: String.t}
+end
diff --git a/lib/recaptcha/template.ex b/lib/recaptcha/template.ex
new file mode 100644
index 0000000..d644266
--- /dev/null
+++ b/lib/recaptcha/template.ex
@@ -0,0 +1,25 @@
+defmodule Recaptcha.Template do
+ @moduledoc """
+ Responsible for rendering boilerplate recaptcha HTML code, supports noscript fallback.
+
+ Currently the [explicit render](https://developers.google.com/recaptcha/docs/display#explicit_render) functionality
+ is not supported.
+
+ In future this module may be separated out into a Phoenix specific library.
+ """
+ require Elixir.EEx
+
+ EEx.function_from_file :defp, :render_template, "lib/template.html.eex", [:assigns]
+
+ @public_key Application.get_env(:recaptcha, :public_key)
+
+ @doc """
+ Returns a string with reCAPTCHA code
+
+ To convert the string to html code, use Phoenix.HTML.Raw/1 method
+ """
+ def display(options \\ []) do
+ public_key = options[:public_key] || @public_key
+ render_template(public_key: public_key, options: options)
+ end
+end