defmodule MishkaAuth.Helper.Captcha.Google do
@type remoteip() :: String.t()
@type response() :: String.t()
@type secret() :: String.t()
@type provider() :: atom()
# Google doc
#
#
#
# "success" => true
# %{
# "action" => "submit",
# "challenge_ts" => "2020-10-05T14:44:34Z",
# "hostname" => "localhost",
# "score" => 0.9,
# "success" => true
# }
# "success" => false
# %{
# "error-codes" => ["invalid-input-response"],
# "success" => false}
# }
@google_link "https://www.google.com/recaptcha/api/siteverify"
@spec verify(response(), remoteip(), secret()) ::
{:error, :google_response, :unexpected_error_or_not_active}
| {:error, :captcha_verify, :google, any}
| {:ok, :captcha_verify, :google, map}
def verify(response, remoteip, secret) do
google_sender(response, remoteip, secret)
|> google_response
|> google_converter
end
@spec google_sender(response(), remoteip(), secret()) ::
{:error, HTTPoison.Error.t()}
| {:ok,
%{
:__struct__ => HTTPoison.AsyncResponse | HTTPoison.Response,
optional(:body) => any,
optional(:headers) => [any],
optional(:id) => reference,
optional(:request) => HTTPoison.Request.t(),
optional(:request_url) => any,
optional(:status_code) => integer
}}
def google_sender(response, remoteip, secret) do
body = %{
"secret" => secret,
"response" => response,
"remoteip" => "#{remoteip}"
}
|> URI.encode_query()
HTTPoison.post(
"#{@google_link}",
body,
[
{"Content-Type", "application/x-www-form-urlencoded"},
{"Accept", "text/html"}
],
[timeout: 50_000, recv_timeout: 50_000]
)
end
@spec google_response(any) :: {:error, :google_response, any} | {:ok, :google_response, map}
def google_response(response) do
case response do
{:ok, %HTTPoison.Response{status_code: 200, body: body}} ->
{:ok, :google_response, Jason.decode!(body)}
{:ok, %HTTPoison.Response{status_code: 401}} ->
{:error, :google_response, :no_access}
{:ok, %HTTPoison.Response{status_code: 400}} ->
{:error, :google_response, :bad_data}
{:error, %HTTPoison.Error{reason: reason}} ->
{:error, :google_response, reason}
_ ->
{:error, :google_response, :unexpected_error}
end
end
@spec google_converter(any) ::
{:error, :google_response, :unexpected_error_or_not_active}
| {:error, :captcha_verify, :google, any}
| {:ok, :captcha_verify, :google, map}
def google_converter({:ok, :google_response, %{"error-codes" => reason, "success" => false}}) do
{:error, :captcha_verify, :google, reason}
end
def google_converter({:ok, :google_response, %{"success" => true} = google_params}) do
{:ok, :captcha_verify, :google, google_params}
end
def google_converter({:error, :google_response, reason}) do
{:error, :captcha_verify, :google, reason}
end
def google_converter(_params) do
{:error, :google_response, :unexpected_error_or_not_active}
end
end