From 77ed4e7ca4ef2f5a9c021e6d1e22a5da7dca9d7b Mon Sep 17 00:00:00 2001 From: michaeljguarino Date: Sun, 15 Sep 2024 00:41:47 -0400 Subject: [PATCH] Implement captcha on login will improve login security a tad --- apps/core/mix.exs | 1 + .../graphql/lib/graphql/middleware/captcha.ex | 12 +++++ apps/graphql/lib/graphql/schema/user.ex | 5 ++- .../test/mutations/user_mutation_test.exs | 45 +++++++++++++++++++ config/config.exs | 5 +++ config/test.exs | 4 ++ mix.lock | 11 ++--- schema/schema.graphql | 2 +- www/src/generated/graphql.ts | 1 + 9 files changed, 79 insertions(+), 7 deletions(-) create mode 100644 apps/graphql/lib/graphql/middleware/captcha.ex diff --git a/apps/core/mix.exs b/apps/core/mix.exs index 6fe107e44..ea613ca7d 100644 --- a/apps/core/mix.exs +++ b/apps/core/mix.exs @@ -126,6 +126,7 @@ defmodule Core.MixProject do {:cloudflare, "~> 0.2"}, {:mimic, "~> 1.1", only: :test}, {:google_api_iam, "~> 0.40"}, + {:recaptcha, "~> 3.0", git: "https://github.com/samueljseay/recaptcha"}, {:google_api_cloud_resource_manager, "~> 0.41"}, {:google_api_cloud_billing, "~> 0.23"}, {:google_api_service_usage, "~> 0.18"}, diff --git a/apps/graphql/lib/graphql/middleware/captcha.ex b/apps/graphql/lib/graphql/middleware/captcha.ex new file mode 100644 index 000000000..830cc3ebe --- /dev/null +++ b/apps/graphql/lib/graphql/middleware/captcha.ex @@ -0,0 +1,12 @@ +defmodule GraphQl.Middleware.Captcha do + @behaviour Absinthe.Middleware + import Absinthe.Resolution, only: [put_result: 2] + + def call(%{arguments: %{captcha: captcha}} = res, _) when is_binary(captcha) do + case Recaptcha.verify(captcha) |> IO.inspect() do + {:ok, _} -> res + _ -> put_result(res, {:error, "captcha validation failed"}) + end + end + def call(res, _), do: res +end diff --git a/apps/graphql/lib/graphql/schema/user.ex b/apps/graphql/lib/graphql/schema/user.ex index 8bb35bbc2..623677821 100644 --- a/apps/graphql/lib/graphql/schema/user.ex +++ b/apps/graphql/lib/graphql/schema/user.ex @@ -7,7 +7,7 @@ defmodule GraphQl.Schema.User do Payments, Account } - alias GraphQl.Middleware.{Authenticated, AllowJwt, RateLimit, Differentiate, CheckOrigin} + alias GraphQl.Middleware.{Authenticated, AllowJwt, RateLimit, Differentiate, CheckOrigin, Captcha} ecto_enum :notification_type, Schema.Notification.Type ecto_enum :reset_token_type, Schema.ResetToken.Type @@ -470,6 +470,9 @@ defmodule GraphQl.Schema.User do arg :email, non_null(:string) arg :password, non_null(:string) arg :device_token, :string + arg :captcha, :string + + middleware Captcha safe_resolve &User.login_user/2 end diff --git a/apps/graphql/test/mutations/user_mutation_test.exs b/apps/graphql/test/mutations/user_mutation_test.exs index c33133904..13a85faf9 100644 --- a/apps/graphql/test/mutations/user_mutation_test.exs +++ b/apps/graphql/test/mutations/user_mutation_test.exs @@ -25,6 +25,51 @@ defmodule GraphQl.UserMutationTest do assert found["jwt"] end + test "it will validate captchas" do + {:ok, user} = Users.create_user(%{ + name: "Michael Guarino", + email: "mjg@plural.sh", + password: "super strong password" + }) + + {:ok, %{data: %{"login" => found}}} = run_query(""" + mutation Login($email: String!, $password: String!, $captcha: String!) { + login(email: $email, password: $password, captcha: $captcha) { + id + jwt + } + } + """, %{ + "email" => "mjg@plural.sh", + "password" => "super strong password", + "captcha" => "valid_response" + }, %{origin: "https://app.plural.sh"}) + + assert found["id"] == user.id + assert found["jwt"] + end + + test "it will fail on invalid captchas" do + {:ok, user} = Users.create_user(%{ + name: "Michael Guarino", + email: "mjg@plural.sh", + password: "super strong password" + }) + + {:ok, %{errors: [_ | _]}} = run_query(""" + mutation Login($email: String!, $password: String!, $captcha: String!) { + login(email: $email, password: $password, captcha: $captcha) { + id + jwt + } + } + """, %{ + "email" => "mjg@plural.sh", + "password" => "super strong password", + "captcha" => "invalid_response" + }, %{origin: "https://app.plural.sh"}) + end + test "invalid origins fail" do {:ok, _} = Users.create_user(%{ name: "Michael Guarino", diff --git a/config/config.exs b/config/config.exs index 926581da9..484bf1172 100644 --- a/config/config.exs +++ b/config/config.exs @@ -188,4 +188,9 @@ config :core, :oidc_providers, discovery_document_uri: "https://token.actions.githubusercontent.com/.well-known/openid-configuration", ] +config :recaptcha, + json_library: Jason, + public_key: {:system, "RECAPTCHA_SITE_KEY"}, + secret: {:system, "RECAPTURE_SECRET_KEY"} + import_config "#{config_env()}.exs" diff --git a/config/test.exs b/config/test.exs index ad42eb1da..a0c191064 100644 --- a/config/test.exs +++ b/config/test.exs @@ -93,3 +93,7 @@ config :core, sysbox_emails: ["sysbox@plural.sh"], cockroach_parameters: [sslmode: "allow"], bootstrap_ssl: false + +config :recaptcha, + http_client: Recaptcha.Http.MockClient, + secret: "6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe" diff --git a/mix.lock b/mix.lock index 2438f28e1..ffd49f7af 100644 --- a/mix.lock +++ b/mix.lock @@ -22,7 +22,7 @@ "briefly": {:git, "https://github.com/CargoSense/briefly", "b0fd495bf0c5ef2c44de2791a8cc7a20813c7d36", [ref: "b0fd495bf0c5ef2c44de2791a8cc7a20813c7d36"]}, "bunt": {:hex, :bunt, "0.2.1", "e2d4792f7bc0ced7583ab54922808919518d0e57ee162901a16a1b6664ef3b14", [:mix], [], "hexpm", "a330bfb4245239787b15005e66ae6845c9cd524a288f0d141c148b02603777a5"}, "castore": {:hex, :castore, "0.1.22", "4127549e411bedd012ca3a308dede574f43819fe9394254ca55ab4895abfa1a2", [:mix], [], "hexpm", "c17576df47eb5aa1ee40cc4134316a99f5cad3e215d5c77b8dd3cfef12a22cac"}, - "certifi": {:hex, :certifi, "2.9.0", "6f2a475689dd47f19fb74334859d460a2dc4e3252a3324bd2111b8f0429e7e21", [:rebar3], [], "hexpm", "266da46bdb06d6c6d35fde799bcb28d36d985d424ad7c08b5bb48f5b5cdd4641"}, + "certifi": {:hex, :certifi, "2.12.0", "2d1cca2ec95f59643862af91f001478c9863c2ac9cb6e2f89780bfd8de987329", [:rebar3], [], "hexpm", "ee68d85df22e554040cdb4be100f33873ac6051387baf6a8f6ce82272340ff1c"}, "cloudflare": {:hex, :cloudflare, "0.2.0", "e754fab186d5c9cd30cafdd336b8150b227e31e45ea6bd279d3c6cb20ff21ac1", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:restlax, "~> 0.1", [hex: :restlax, repo: "hexpm", optional: false]}], "hexpm", "0c2fced3058d92f8732c9911e309496a2f26f6f6d0f8216b8a2c62c2f8028748"}, "combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"}, "comeonin": {:hex, :comeonin, "5.3.3", "2c564dac95a35650e9b6acfe6d2952083d8a08e4a89b93a481acb552b325892e", [:mix], [], "hexpm", "3e38c9c2cb080828116597ca8807bb482618a315bfafd98c90bc22a821cc84df"}, @@ -74,7 +74,7 @@ "google_gax": {:hex, :google_gax, "0.4.1", "310105070626013712c56f8007b6ff7b4ead02ecad1efe7888350c6eaba52783", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:poison, ">= 3.0.0 and < 5.0.0", [hex: :poison, repo: "hexpm", optional: false]}, {:tesla, "~> 1.2", [hex: :tesla, repo: "hexpm", optional: false]}], "hexpm", "aef7dce7e04840c0e611f962475e3223d27d50ebd5e7d8e9e963c5e9e3b1ca79"}, "goth": {:hex, :goth, "1.3.1", "f3e08a7f23ea8992ab92d2e1d5c72ea1a8fbd2fe3a46ad1b08d0620f71374fdc", [:mix], [{:finch, "~> 0.9", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:jose, "~> 1.10", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "90326c2c0a7acda7fb75fc4a4f0cba84945d8fcb22694d36c9967cec8949937c"}, "guardian": {:hex, :guardian, "1.2.1", "bdc8dd3dbf0fb7216cb6f91c11831faa1a64d39cdaed9a611e37f2413e584983", [:mix], [{:jose, "~> 1.8", [hex: :jose, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.3", [hex: :phoenix, repo: "hexpm", optional: true]}, {:plug, "~> 1.3.3 or ~> 1.4", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "723fc404edfb7bd5cba4cd83329b352037f102aa97468f44e58ac7f47c136a98"}, - "hackney": {:hex, :hackney, "1.18.1", "f48bf88f521f2a229fc7bae88cf4f85adc9cd9bcf23b5dc8eb6a1788c662c4f6", [:rebar3], [{:certifi, "~> 2.9.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a4ecdaff44297e9b5894ae499e9a070ea1888c84afdd1fd9b7b2bc384950128e"}, + "hackney": {:hex, :hackney, "1.18.2", "d7ff544ddae5e1cb49e9cf7fa4e356d7f41b283989a1c304bfc47a8cc1cf966f", [:rebar3], [{:certifi, "~> 2.12.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "af94d5c9f97857db257090a4a10e5426ecb6f4918aa5cc666798566ae14b65fd"}, "hammer": {:hex, :hammer, "6.1.0", "f263e3c3e9946bd410ea0336b2abe0cb6260af4afb3a221e1027540706e76c55", [:make, :mix], [{:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}], "hexpm", "b47e415a562a6d072392deabcd58090d8a41182cf9044cdd6b0d0faaaf68ba57"}, "hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"}, "httpoison": {:hex, :httpoison, "1.8.2", "9eb9c63ae289296a544842ef816a85d881d4a31f518a0fec089aaa744beae290", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "2bb350d26972e30c96e2ca74a1aaf8293d61d0742ff17f01e0279fef11599921"}, @@ -96,7 +96,7 @@ "meck": {:hex, :meck, "0.8.13", "ffedb39f99b0b99703b8601c6f17c7f76313ee12de6b646e671e3188401f7866", [:rebar3], [], "hexpm"}, "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, "mime": {:hex, :mime, "1.6.0", "dabde576a497cef4bbdd60aceee8160e02a6c89250d6c0b29e56c0dfb00db3d2", [:mix], [], "hexpm", "31a1a8613f8321143dde1dafc36006a17d28d02bdfecb9e95a880fa7aabd19a7"}, - "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"}, + "mimerl": {:hex, :mimerl, "1.3.0", "d0cd9fc04b9061f82490f6581e0128379830e78535e017f7780f37fea7545726", [:rebar3], [], "hexpm", "a1e15a50d1887217de95f0b9b0793e32853f7c258a5cd227650889b38839fe9d"}, "mimic": {:hex, :mimic, "1.1.3", "3bad83d5271b4faa7bbfef587417a6605cbbc802a353395d446a1e5f46fe7115", [:mix], [], "hexpm", "0d93cb8fcd00a1013bae56050755879050bb9b8ef0c3d51b6fec5a2f1fc33d66"}, "mint": {:hex, :mint, "1.4.2", "50330223429a6e1260b2ca5415f69b0ab086141bc76dc2fbf34d7c389a6675b2", [:mix], [{:castore, "~> 0.1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "ce75a5bbcc59b4d7d8d70f8b2fc284b1751ffb35c7b6a6302b5192f8ab4ddd80"}, "mint_web_socket": {:hex, :mint_web_socket, "1.0.4", "0b539116dbb3d3f861cdf5e15e269a933cb501c113a14db7001a3157d96ffafd", [:mix], [{:mint, ">= 1.4.1 and < 2.0.0-0", [hex: :mint, repo: "hexpm", optional: false]}], "hexpm", "027d4c5529c45a4ba0ce27a01c0f35f284a5468519c045ca15f43decb360a991"}, @@ -110,7 +110,7 @@ "oauth2": {:hex, :oauth2, "2.0.0", "338382079fe16c514420fa218b0903f8ad2d4bfc0ad0c9f988867dfa246731b0", [:mix], [{:hackney, "~> 1.13", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "881b8364ac7385f9fddc7949379cbe3f7081da37233a1aa7aab844670a91e7e7"}, "openid_connect": {:git, "https://github.com/pluralsh/openid_connect", "c3b2701b9adbe01fd89bbd09816ffa6c9e4a825e", []}, "parallax": {:hex, :parallax, "1.0.0", "decfed51b2d41c88ea4398d3bd8fadd2ceb1f913cf0f44ef2cb41e732ace31f5", [:mix], [], "hexpm", "8a8b91685bfacb483ff9370b98844ee01107544a11ee49b5f1d98df0eff2b1e4"}, - "parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"}, + "parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"}, "phoenix": {:hex, :phoenix, "1.6.15", "0a1d96bbc10747fd83525370d691953cdb6f3ccbac61aa01b4acb012474b047d", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 1.0 or ~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d70ab9fbf6b394755ea88b644d34d79d8b146e490973151f248cacd122d20672"}, "phoenix_ecto": {:hex, :phoenix_ecto, "4.4.0", "0672ed4e4808b3fbed494dded89958e22fb882de47a97634c0b13e7b0b5f7720", [:mix], [{:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "09864e558ed31ee00bd48fcc1d4fc58ae9678c9e81649075431e69dbabb43cc1"}, "phoenix_html": {:hex, :phoenix_html, "3.2.0", "1c1219d4b6cb22ac72f12f73dc5fad6c7563104d083f711c3fcd8551a1f4ae11", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "36ec97ba56d25c0136ef1992c37957e4246b649d620958a1f9fa86165f8bc54f"}, @@ -136,6 +136,7 @@ "quantum": {:hex, :quantum, "2.3.4", "72a0e8855e2adc101459eac8454787cb74ab4169de6ca50f670e72142d4960e9", [:mix], [{:calendar, "~> 0.17", [hex: :calendar, repo: "hexpm", optional: true]}, {:crontab, "~> 1.1", [hex: :crontab, repo: "hexpm", optional: false]}, {:gen_stage, "~> 0.12", [hex: :gen_stage, repo: "hexpm", optional: false]}, {:swarm, "~> 3.3", [hex: :swarm, repo: "hexpm", optional: false]}, {:timex, "~> 3.1", [hex: :timex, repo: "hexpm", optional: true]}], "hexpm"}, "rabbit_common": {:hex, :rabbit_common, "3.11.3", "cf1466d99ba1b0788b046f6481c567cdd02580fdf277ba86e9417b5cc5eb6f1a", [:make, :rebar3], [{:credentials_obfuscation, "3.2.0", [hex: :credentials_obfuscation, repo: "hexpm", optional: false]}, {:recon, "2.5.2", [hex: :recon, repo: "hexpm", optional: false]}, {:thoas, "0.4.0", [hex: :thoas, repo: "hexpm", optional: false]}], "hexpm", "b997df691f8a8ea12b52a3fbc5b5b6ca862879544162e63e7679a3f8d0ce22a4"}, "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"}, + "recaptcha": {:git, "https://github.com/samueljseay/recaptcha", "71cd746be987f6834c1a933f5d2f934350e55060", []}, "recon": {:hex, :recon, "2.5.2", "cba53fa8db83ad968c9a652e09c3ed7ddcc4da434f27c3eaa9ca47ffb2b1ff03", [:mix, :rebar3], [], "hexpm", "2c7523c8dee91dff41f6b3d63cba2bd49eb6d2fe5bf1eec0df7f87eb5e230e1c"}, "remote_ip": {:hex, :remote_ip, "0.2.1", "cd27cd8ea54ecaaf3532776ff4c5e353b3804e710302e88c01eadeaaf42e7e24", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:inet_cidr, "~> 1.0", [hex: :inet_cidr, repo: "hexpm", optional: false]}, {:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "2e7ab1a461cc3cd5719f37e116a08f45c8b8493923063631b164315d6b7ee8e0"}, "req": {:hex, :req, "0.4.14", "103de133a076a31044e5458e0f850d5681eef23dfabf3ea34af63212e3b902e2", [:mix], [{:aws_signature, "~> 0.3.2", [hex: :aws_signature, repo: "hexpm", optional: true]}, {:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:nimble_ownership, "~> 0.2.0 or ~> 0.3.0", [hex: :nimble_ownership, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "2ddd3d33f9ab714ced8d3c15fd03db40c14dbf129003c4a3eb80fac2cc0b1b08"}, @@ -145,7 +146,7 @@ "shards": {:hex, :shards, "1.0.1", "1bdbbf047db27f3c3eb800a829d4a47062c84d5543cbfebcfc4c14d038bf9220", [:make, :rebar3], [], "hexpm", "2c57788afbf053c4024366772892beee89b8b72e884e764fb0a075dfa7442041"}, "slipstream": {:hex, :slipstream, "1.1.1", "7e56f62f1a9ee81351e3c36f57b9b187e00dc2f470e70ba46ea7ad16e80b061f", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mint_web_socket, "~> 0.2 or ~> 1.0", [hex: :mint_web_socket, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.1 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c20e420cde1654329d38ec3aa1c0e4debbd4c91ca421491e7984ad4644e638a6"}, "sobelow": {:hex, :sobelow, "0.11.1", "23438964486f8112b41e743bbfd402da3e5b296fdc9eacab29914b79c48916dd", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "9897363a7eff96f4809304a90aad819e2ad5e5d24db547af502885146746a53c"}, - "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"}, + "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"}, "stripity_stripe": {:hex, :stripity_stripe, "2.17.2", "6e4c5f0b2deb3d3411f91e23fedbe9db4c031a52dfeb7074b4df4fdd22ad32cd", [:mix], [{:hackney, "~> 1.15", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}, {:uri_query, "~> 0.1.2", [hex: :uri_query, repo: "hexpm", optional: false]}], "hexpm", "42bffb591d34f3cfa95cb37e862140e44a61ca4c64578bf7bb591ba60c6a66bc"}, "swarm": {:hex, :swarm, "3.4.0", "64f8b30055d74640d2186c66354b33b999438692a91be275bb89cdc7e401f448", [:mix], [{:gen_state_machine, "~> 2.0", [hex: :gen_state_machine, repo: "hexpm", optional: false]}, {:libring, "~> 1.0", [hex: :libring, repo: "hexpm", optional: false]}], "hexpm", "94884f84783fc1ba027aba8fe8a7dae4aad78c98e9f9c76667ec3471585c08c6"}, "sweet_xml": {:hex, :sweet_xml, "0.7.3", "debb256781c75ff6a8c5cbf7981146312b66f044a2898f453709a53e5031b45b", [:mix], [], "hexpm", "e110c867a1b3fe74bfc7dd9893aa851f0eed5518d0d7cad76d7baafd30e4f5ba"}, diff --git a/schema/schema.graphql b/schema/schema.graphql index f24bb3bd3..53982340a 100644 --- a/schema/schema.graphql +++ b/schema/schema.graphql @@ -219,7 +219,7 @@ type RootQueryType { } type RootMutationType { - login(email: String!, password: String!, deviceToken: String): User + login(email: String!, password: String!, deviceToken: String, captcha: String): User deviceLogin: DeviceLogin diff --git a/www/src/generated/graphql.ts b/www/src/generated/graphql.ts index e7eee7752..7f36b98c5 100644 --- a/www/src/generated/graphql.ts +++ b/www/src/generated/graphql.ts @@ -3397,6 +3397,7 @@ export type RootMutationTypeLinkPublisherArgs = { export type RootMutationTypeLoginArgs = { + captcha?: InputMaybe; deviceToken?: InputMaybe; email: Scalars['String']['input']; password: Scalars['String']['input'];