diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..69550cd --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,20 @@ +on: + push: + tags: + - '*' + +jobs: + publish: + env: + HEX_API_KEY: ${{ secrets.HEX_API_KEY }} + runs-on: ubuntu-latest + container: + image: "hexpm/elixir:1.14.3-erlang-25.2.2-alpine-3.17.0" + steps: + - name: Check out + uses: actions/checkout@v3 + - run: mix local.rebar --force + - run: mix local.hex --force + - run: mix do deps.get, compile + - name: Publish + run: mix hex.publish --yes diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..59c8703 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,41 @@ +name: Run Elixir Tests + +on: + push: + branches: + - master + - github-actions-support + pull_request: + +concurrency: + group: ci-${{ github.ref }} + cancel-in-progress: true + +jobs: + elixir_test: + name: Run Elixir Tests + runs-on: ubuntu-latest + strategy: + matrix: + image: + - "hexpm/elixir:1.10.4-erlang-23.3.4-alpine-3.16.0" + - "hexpm/elixir:1.11.4-erlang-24.3-alpine-3.17.0" + - "hexpm/elixir:1.12.3-erlang-24.3-alpine-3.17.0" + - "hexpm/elixir:1.13.4-erlang-25.2-alpine-3.17.0" + - "hexpm/elixir:1.14.3-erlang-25.2.2-alpine-3.17.0" + container: + image: ${{ matrix.image }} + env: + MIX_ENV: test + steps: + - run: apk add git + - uses: actions/checkout@v3 + - run: mix local.rebar --force + - run: mix local.hex --force + - run: mix do deps.get + - run: mix test + - run: mix format --check-formatted + - run: mix credo --strict + - run: mix coveralls.github + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 840104d..0000000 --- a/.travis.yml +++ /dev/null @@ -1,22 +0,0 @@ -language: elixir -sudo: false - -elixir: - - 1.6 - - 1.7 - - 1.8 - - 1.9 - -otp_release: - - 20.0 - - 21.0 - -env: MIX_ENV=test - -script: - - mix format --check-formatted - - mix credo --strict - - mix coveralls.travis - -notifications: - email: false diff --git a/README.md b/README.md index 83dcabc..6bbd5c8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,5 @@ # Recaptcha -[![Build Status](https://travis-ci.org/samueljseay/recaptcha.svg?branch=master)](https://travis-ci.org/samueljseay/recaptcha) [![Coverage Status](https://coveralls.io/repos/github/samueljseay/recaptcha/badge.svg?branch=master)](https://coveralls.io/github/samueljseay/recaptcha) [![Module Version](https://img.shields.io/hexpm/v/recaptcha.svg)](https://hex.pm/packages/recaptcha) [![Hex Docs](https://img.shields.io/badge/hex-docs-lightgreen.svg)](https://hexdocs.pm/recaptcha/) diff --git a/lib/recaptcha.ex b/lib/recaptcha.ex index 41661b4..edba75d 100644 --- a/lib/recaptcha.ex +++ b/lib/recaptcha.ex @@ -8,7 +8,7 @@ defmodule Recaptcha do alias Recaptcha.{Config, Http, Response} - @http_client Application.get_env(:recaptcha, :http_client, Http) + @http_client Application.compile_env(:recaptcha, :http_client, Http) @doc """ Verifies a reCAPTCHA response string. @@ -26,12 +26,12 @@ defmodule Recaptcha do """ @spec verify(String.t(), Keyword.t()) :: - {:ok, Response.t()} | {:error, [atom]} + {:ok, Response.t()} | {:error, [atom]} def verify(response, options \\ []) do verification = @http_client.request_verification( request_body(response, options), - options + options ) case verification do diff --git a/lib/recaptcha/http.ex b/lib/recaptcha/http.ex index f2734d9..43bef39 100644 --- a/lib/recaptcha/http.ex +++ b/lib/recaptcha/http.ex @@ -36,18 +36,19 @@ defmodule Recaptcha.Http do }) """ - @spec request_verification(binary, Keyword.t) :: {:ok, map} | {:error, [atom]} + @spec request_verification(binary, Keyword.t()) :: + {:ok, map} | {:error, [atom]} def request_verification(body, options \\ []) do timeout = options[:timeout] || Config.get_env(:recaptcha, :timeout, 5000) url = Config.get_env(:recaptcha, :verify_url, @default_verify_url) json = Application.get_env(:recaptcha, :json_library, Jason) opts = [{:timeout, timeout} | options] + result = with {:ok, response} <- - HTTPoison.post(url, body, @headers, opts), - {:ok, data} <- json.decode(response.body) do - {:ok, data} + HTTPoison.post(url, body, @headers, opts) do + json.decode(response.body) end case result do diff --git a/mix.exs b/mix.exs index a9cd256..eb39dd7 100644 --- a/mix.exs +++ b/mix.exs @@ -2,13 +2,13 @@ defmodule Recaptcha.Mixfile do use Mix.Project @source_url "https://github.com/samueljseay/recaptcha" - @version "3.1.0" + @version "4.0.0" def project do [ app: :recaptcha, version: @version, - elixir: "~> 1.6", + elixir: "~> 1.10", description: description(), deps: deps(), package: package(), @@ -48,10 +48,10 @@ defmodule Recaptcha.Mixfile do [ {:httpoison, ">= 0.12.0"}, {:jason, "~> 1.2", optional: true}, - {:credo, "~> 1.0", only: [:dev, :test], runtime: false}, + {:credo, "~> 1.6", only: [:dev, :test], runtime: false}, {:ex_doc, ">= 0.0.0", only: :dev, runtime: false}, {:dialyxir, "~> 0.5", only: [:dev]}, - {:excoveralls, "~> 0.7.1", only: :test} + {:excoveralls, "~> 0.15.3", only: :test} ] end diff --git a/mix.lock b/mix.lock index 73ed202..cd85315 100644 --- a/mix.lock +++ b/mix.lock @@ -1,16 +1,17 @@ %{ "bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm", "7af5c7e09fe1d40f76c8e4f9dd2be7cebd83909f31fee7cd0e9eadc567da8353"}, "certifi": {:hex, :certifi, "2.5.2", "b7cfeae9d2ed395695dd8201c57a2d019c0c43ecaf8b8bcb9320b40d6662f340", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm", "3b3b5f36493004ac3455966991eaf6e768ce9884693d9968055aeeeb1e575040"}, - "credo": {:hex, :credo, "1.4.0", "92339d4cbadd1e88b5ee43d427b639b68a11071b6f73854e33638e30a0ea11f5", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "1fd3b70dce216574ce3c18bdf510b57e7c4c85c2ec9cad4bff854abaf7e58658"}, + "credo": {:hex, :credo, "1.6.6", "f51f8d45db1af3b2e2f7bee3e6d3c871737bda4a91bff00c5eec276517d1a19c", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "625520ce0984ee0f9f1f198165cd46fa73c1e59a17ebc520038b8fce056a5bdc"}, "dialyxir": {:hex, :dialyxir, "0.5.1", "b331b091720fd93e878137add264bac4f644e1ddae07a70bf7062c7862c4b952", [:mix], [], "hexpm", "6c32a70ed5d452c6650916555b1f96c79af5fc4bf286997f8b15f213de786f73"}, "earmark_parser": {:hex, :earmark_parser, "1.4.13", "0c98163e7d04a15feb62000e1a891489feb29f3d10cb57d4f845c405852bbef8", [:mix], [], "hexpm", "d602c26af3a0af43d2f2645613f65841657ad6efc9f0e361c3b6c06b578214ba"}, "ex_doc": {:hex, :ex_doc, "0.24.2", "e4c26603830c1a2286dae45f4412a4d1980e1e89dc779fcd0181ed1d5a05c8d9", [:mix], [{:earmark_parser, "~> 1.4.0", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "e134e1d9e821b8d9e4244687fb2ace58d479b67b282de5158333b0d57c6fb7da"}, - "excoveralls": {:hex, :excoveralls, "0.7.5", "339e433e5d3bce09400dc8de7b9040741a409c93917849916c136a0f51fdc183", [:mix], [{:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: false]}, {:hackney, ">= 0.12.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "36422936691b6a8a728fe42c528e7b2719b2fde1a56d19fc7e3de31cb2271017"}, + "excoveralls": {:hex, :excoveralls, "0.15.3", "54bb54043e1cf5fe431eb3db36b25e8fd62cf3976666bafe491e3fa5e29eba47", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "f8eb5d8134d84c327685f7bb8f1db4147f1363c3c9533928234e496e3070114e"}, "exjsx": {:hex, :exjsx, "4.0.0", "60548841e0212df401e38e63c0078ec57b33e7ea49b032c796ccad8cde794b5c", [:mix], [{:jsx, "~> 2.8.0", [hex: :jsx, repo: "hexpm", optional: false]}], "hexpm", "32e95820a97cffea67830e91514a2ad53b888850442d6d395f53a1ac60c82e07"}, + "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, "hackney": {:hex, :hackney, "1.16.0", "5096ac8e823e3a441477b2d187e30dd3fff1a82991a806b2003845ce72ce2d84", [:rebar3], [{:certifi, "2.5.2", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.1", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.0", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.6", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "3bf0bebbd5d3092a3543b783bf065165fa5d3ad4b899b836810e513064134e18"}, "httpoison": {:hex, :httpoison, "1.7.0", "abba7d086233c2d8574726227b6c2c4f6e53c4deae7fe5f6de531162ce9929a0", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "975cc87c845a103d3d1ea1ccfd68a2700c211a434d8428b10c323dc95dc5b980"}, "idna": {:hex, :idna, "6.0.1", "1d038fb2e7668ce41fbf681d2c45902e52b3cb9e9c77b55334353b222c2ee50c", [:rebar3], [{:unicode_util_compat, "0.5.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a02c8a1c4fd601215bb0b0324c8a6986749f807ce35f25449ec9e69758708122"}, - "jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fdf843bca858203ae1de16da2ee206f53416bbda5dc8c9e78f43243de4bc3afe"}, + "jason": {:hex, :jason, "1.4.0", "e855647bc964a44e2f67df589ccf49105ae039d4179db7f6271dfd3843dc27e6", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "79a3791085b2a0f743ca04cec0f7be26443738779d09302e01318f97bdb82121"}, "jsx": {:hex, :jsx, "2.8.3", "a05252d381885240744d955fbe3cf810504eb2567164824e19303ea59eef62cf", [:mix, :rebar3], [], "hexpm", "fc3499fed7a726995aa659143a248534adc754ebd16ccd437cd93b649a95091f"}, "makeup": {:hex, :makeup, "1.0.5", "d5a830bc42c9800ce07dd97fa94669dfb93d3bf5fcf6ea7a0c67b2e0e4a7f26c", [:mix], [{:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cfa158c02d3f5c0c665d0af11512fed3fba0144cf1aadee0f2ce17747fba2ca9"}, "makeup_elixir": {:hex, :makeup_elixir, "0.15.1", "b5888c880d17d1cc3e598f05cdb5b5a91b7b17ac4eaf5f297cb697663a1094dd", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.1", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "db68c173234b07ab2a07f645a5acdc117b9f99d69ebf521821d89690ae6c6ec8"}, diff --git a/test/recaptcha_test.exs b/test/recaptcha_test.exs index 15b9ba7..d2fc246 100644 --- a/test/recaptcha_test.exs +++ b/test/recaptcha_test.exs @@ -4,9 +4,13 @@ defmodule RecaptchaTest do # see https://developers.google.com/recaptcha/docs/faq#id-like-to-run-automated-tests-with-recaptcha-v2-what-should-i-do @google_test_secret "6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe" - test "When the supplied g-recaptcha-response is invalid, multiple errors are returned" do - assert {:error, messages} = Recaptcha.verify("not_valid") - assert messages == [:invalid_input_response, :invalid_input_secret] + test "When an invalid secret is provided, invalid_input_secret is returned" do + assert {:error, messages} = + Recaptcha.verify("not_valid", + secret: "#{@google_test_secret}_bogus_secret" + ) + + assert messages == [:invalid_input_secret] end test "When a valid response is supplied, a success response is returned" do @@ -35,7 +39,8 @@ defmodule RecaptchaTest do test "Passes other options to the http client" do Recaptcha.verify("valid_response", timeout: 25_000, recv_timeout: 5_000) - assert_received {:request_verification, _, [timeout: 25_000, recv_timeout: 5_000]} + assert_received {:request_verification, _, + [timeout: 25_000, recv_timeout: 5_000]} end test "Remote IP is used in the request body when it is passed into verify/2 as an option" do