1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
defmodule Recaptcha do
@moduledoc """
A module for verifying reCAPTCHA version 2.0 response strings.
See the [documentation](https://developers.google.com/recaptcha/docs/verify)
for more details.
"""
alias Recaptcha.Config
@http_client Application.get_env(:recaptcha, :http_client, Recaptcha.Http)
@doc """
Verifies a reCAPTCHA response string.
## Options
* `:timeout` - the timeout for the request (defaults to 5000ms)
* `:secret` - the secret key used by recaptcha (defaults to the secret
provided in application config)
* `:remote_ip` - the IP address of the user (optional and not set by default)
## Example
{:ok, api_response} = Recaptcha.verify("response_string")
"""
@spec verify(String.t, [timeout: integer, secret: String.t,
remote_ip: String.t]) :: {:ok, Recaptcha.Response.t} |
{:error, [atom]}
def verify(response, options \\ [])
def verify(nil = _response, _) do
{:error, [:invalid_input_response]}
end
def verify(response, options) do
case @http_client.request_verification(
request_body(response, options),
Keyword.take(options, [:timeout])
) do
{:error, errors} ->
{:error, errors}
{:ok, %{"success" => false, "error-codes" => errors}} ->
{:error, Enum.map(errors, fn(error) -> atomise_api_error(error) end)}
{:ok, %{"success" => true, "challenge_ts" => timestamp, "hostname" => host}} ->
{:ok, %Recaptcha.Response{challenge_ts: timestamp, hostname: host}}
{:ok, %{"success" => false, "challenge_ts" => _timestamp, "hostname" => _host}} ->
{:error, [:challenge_failed]}
end
end
defp request_body(response, options) do
body_options = Keyword.take(options, [:remote_ip, :secret])
application_options = [secret: Config.get_env(:recaptcha, :secret)]
# override application secret with options secret if it exists
application_options
|> Keyword.merge(body_options)
|> Keyword.put(:response, response)
|> URI.encode_query
end
defp atomise_api_error(error) do
error
|> String.replace("-", "_")
|> String.to_atom
end
end
|