From cc0d961cfd2c70df3bb1dacd41763aea7143ebcd Mon Sep 17 00:00:00 2001 From: Benjamin Philip Date: Tue, 14 Dec 2021 15:20:14 +0530 Subject: [PATCH 01/13] Add web auth flow code This is some code that should work for the WebAuth flow in theory. Unfortunately, I have no way of testing, so this code may not actually work. This commit adds a experimental web auth flow task. --- lib/hex/api/web_auth.ex | 50 +++++++++++++++++++++++++++++++++++++++ lib/mix/tasks/hex.ex | 46 +++++++++++++++++++++++++++++++++++ lib/mix/tasks/hex.user.ex | 4 +++- 3 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 lib/hex/api/web_auth.ex diff --git a/lib/hex/api/web_auth.ex b/lib/hex/api/web_auth.ex new file mode 100644 index 00000000..52a76f81 --- /dev/null +++ b/lib/hex/api/web_auth.ex @@ -0,0 +1,50 @@ +defmodule Hex.API.WebAuth do + @moduledoc false + + alias Hex.API + + def get_code(key_name) do + API.request(:post, nil, "login/web_auth/code", %{key_name: key_name}) + end + + def submit_in_browser() do + Task.start(fn -> + "Open link in browser?" + |> Hex.Shell.format() + |> Hex.Shell.yes?() + |> open("https://hex.pm/login/web_auth") + end) + end + + def access_key(device_code) do + Hex.API.check_write_api() + + fn x -> access_key_task(x) end + |> Task.async() + |> Task.await(%{device_code: device_code}, 5 * 60 * 1000) + end + + defp access_key_task(params) do + case API.request(:post, nil, "login/web_auth/access_key", params) do + {:ok, {_code, %{"write_key" => write_key, "read_key" => read_key}, _headers}} -> + %{write_key: write_key, read_key: read_key} + + {:ok, {_code, %{"error" => "request to be verified"}, _headers}} -> + access_key_task(params) + end + end + + defp open(bool, url) + defp open(false, _url), do: :ok + + defp open(true, url) do + {cmd, args} = + case :os.type() do + {:unix, :darwin} -> {"open", [url]} + {:unix, _} -> {"xdg-open", [url]} + {:win32, _} -> {"cmd", ["/c", "start", url]} + end + + System.cmd(cmd, args) + end +end diff --git a/lib/mix/tasks/hex.ex b/lib/mix/tasks/hex.ex index 5ab94996..5489a79a 100644 --- a/lib/mix/tasks/hex.ex +++ b/lib/mix/tasks/hex.ex @@ -124,6 +124,52 @@ defmodule Mix.Tasks.Hex do @doc false def auth(opts \\ []) do + if opts[:web] do + web_auth(opts) + else + normal_auth(opts) + end + end + + defp web_auth(opts \\ []) do + request = + opts[:key_name] + |> api_key_name("WebAuth") + |> Hex.API.WebAuth.get_code() + + device_code = request["device_code"] + user_code = request["user_code"] + + """ + First copy your one-time code: #{user_code} + Paste this code at #{@submit_code_url}...\n\n + """ + |> Hex.Shell.format() + |> Hex.Shell.info() + + Hex.API.WebAuth.submit_in_browser() + + keys = Hex.API.WebAuth.access_key(device_code) + + write_key = keys["write_key"] + read_key = keys["read_key"] + + """ + You have authenticated Hex using WebAuth. + + However, Hex requires you to have a local password that applies + only to this machine for security purposes. + + Please enter it. + """ + |> Hex.Shell.info() + + prompt_encrypt_key(write_key, read_key) + + {:ok, write_key, read_key} + end + + defp normal_auth(opts \\ []) do username = Hex.Shell.prompt("Username:") |> Hex.Stdlib.string_trim() account_password = Mix.Tasks.Hex.password_get("Account password:") |> Hex.Stdlib.string_trim() Mix.Tasks.Hex.generate_all_user_keys(username, account_password, opts) diff --git a/lib/mix/tasks/hex.user.ex b/lib/mix/tasks/hex.user.ex index 3d944e45..b4f6446b 100644 --- a/lib/mix/tasks/hex.user.ex +++ b/lib/mix/tasks/hex.user.ex @@ -19,12 +19,13 @@ defmodule Mix.Tasks.Hex.User do Authorizes a new user on the local machine by generating a new API key and storing it in the Hex config. - $ mix hex.user auth [--key-name KEY_NAME] + $ mix hex.user auth [--key-name KEY_NAME, --web] ### Command line options * `--key-name KEY_NAME` - By default Hex will base the key name on your machine's hostname, use this option to give your own name. + * `--web` - Use WebAuth. ## Deauthorize the user @@ -91,6 +92,7 @@ defmodule Mix.Tasks.Hex.User do @switches [ all: :boolean, key_name: :string, + web: :boolean, permission: [:string, :keep] ] From c36bb412158aeca8fc7c803b9767d4de4020e557 Mon Sep 17 00:00:00 2001 From: Benjamin Philip Date: Tue, 21 Dec 2021 13:23:41 +0530 Subject: [PATCH 02/13] Add API tests --- test/hex/api_test.exs | 20 ++++++++++++++++++++ test/support/hexpm.ex | 4 ++++ 2 files changed, 24 insertions(+) diff --git a/test/hex/api_test.exs b/test/hex/api_test.exs index 5aef7114..700068c8 100644 --- a/test/hex/api_test.exs +++ b/test/hex/api_test.exs @@ -107,6 +107,26 @@ defmodule Hex.APITest do assert {:ok, {401, _, _}} = Hex.API.Key.get(auth_d) end + test "web auth" do + auth = Hexpm.new_key(user: "user", pass: "hunter42") + + # Get request + request = Hex.API.WebAuth.get_code("foobar") + user_code = request["user_code"] + device_code = request["device_code"] + + assert user_code + assert device_code + + Hexpm.submit_web_auth_request(user_code, auth) + + # Access keys + keys = Hex.API.WebAuth.access_key(device_code) + + assert keys.write_key + assert keys.read_key + end + test "owners" do auth = Hexpm.new_key(user: "user", pass: "hunter42") diff --git a/test/support/hexpm.ex b/test/support/hexpm.ex index c10bae54..f2bacbdd 100644 --- a/test/support/hexpm.ex +++ b/test/support/hexpm.ex @@ -233,6 +233,10 @@ defmodule HexTest.Hexpm do [key: secret] end + def submit_web_auth_request(user_code, auth) do + Hex.API.erlang_post_request(nil, "web_auth/submit", %{user_code: user_code}, auth) + end + def new_package(organization, name, version, deps, meta, auth, files \\ nil) do reqs = Enum.filter(deps, fn From e645e5c77d7d8dff0e8226a228ee0067405aa147 Mon Sep 17 00:00:00 2001 From: Benjamin Philip Date: Tue, 21 Dec 2021 16:30:40 +0530 Subject: [PATCH 03/13] Fix API.WebAuth functions --- lib/hex/api/web_auth.ex | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/lib/hex/api/web_auth.ex b/lib/hex/api/web_auth.ex index 52a76f81..5382fd26 100644 --- a/lib/hex/api/web_auth.ex +++ b/lib/hex/api/web_auth.ex @@ -4,7 +4,10 @@ defmodule Hex.API.WebAuth do alias Hex.API def get_code(key_name) do - API.request(:post, nil, "login/web_auth/code", %{key_name: key_name}) + nil + |> API.erlang_post_request("web_auth/code", %{key_name: key_name}) + |> elem(1) + |> elem(1) end def submit_in_browser() do @@ -12,32 +15,37 @@ defmodule Hex.API.WebAuth do "Open link in browser?" |> Hex.Shell.format() |> Hex.Shell.yes?() - |> open("https://hex.pm/login/web_auth") + |> open() end) end def access_key(device_code) do Hex.API.check_write_api() - fn x -> access_key_task(x) end + fn -> access_key_task(%{device_code: device_code}) end |> Task.async() - |> Task.await(%{device_code: device_code}, 5 * 60 * 1000) + |> Task.await(5 * 60 * 1000) end defp access_key_task(params) do - case API.request(:post, nil, "login/web_auth/access_key", params) do + case API.erlang_post_request(nil, "web_auth/access_key", params) do {:ok, {_code, %{"write_key" => write_key, "read_key" => read_key}, _headers}} -> %{write_key: write_key, read_key: read_key} - {:ok, {_code, %{"error" => "request to be verified"}, _headers}} -> + {:ok, {_code, %{"message" => "request to be verified"}, _headers}} -> access_key_task(params) end end - defp open(bool, url) - defp open(false, _url), do: :ok + defp open(bool) + defp open(false), do: :ok + + defp open(true) do + url = + :api_url + |> Hex.State.fetch!() + |> String.replace_suffix("api", "login/web_auth") - defp open(true, url) do {cmd, args} = case :os.type() do {:unix, :darwin} -> {"open", [url]} From fcb4f3e61018174aed24f79d1198c5e1a0db3f7c Mon Sep 17 00:00:00 2001 From: Benjamin Philip Date: Wed, 22 Dec 2021 15:41:10 +0530 Subject: [PATCH 04/13] Add working WebAuth task --- lib/hex/api/web_auth.ex | 9 ++--- lib/mix/tasks/hex.ex | 13 +++++-- test/mix/tasks/hex.user_test.exs | 67 ++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 10 deletions(-) diff --git a/lib/hex/api/web_auth.ex b/lib/hex/api/web_auth.ex index 5382fd26..657555c7 100644 --- a/lib/hex/api/web_auth.ex +++ b/lib/hex/api/web_auth.ex @@ -11,12 +11,9 @@ defmodule Hex.API.WebAuth do end def submit_in_browser() do - Task.start(fn -> - "Open link in browser?" - |> Hex.Shell.format() - |> Hex.Shell.yes?() - |> open() - end) + "Open link in browser?" + |> Hex.Shell.yes?() + |> open() end def access_key(device_code) do diff --git a/lib/mix/tasks/hex.ex b/lib/mix/tasks/hex.ex index 5489a79a..33b842e1 100644 --- a/lib/mix/tasks/hex.ex +++ b/lib/mix/tasks/hex.ex @@ -134,15 +134,20 @@ defmodule Mix.Tasks.Hex do defp web_auth(opts \\ []) do request = opts[:key_name] - |> api_key_name("WebAuth") + |> general_key_name() |> Hex.API.WebAuth.get_code() device_code = request["device_code"] user_code = request["user_code"] + submit_code_url = + :api_url + |> Hex.State.fetch!() + |> String.replace_suffix("api", "login/web_auth") + """ First copy your one-time code: #{user_code} - Paste this code at #{@submit_code_url}...\n\n + Paste this code at #{submit_code_url}... """ |> Hex.Shell.format() |> Hex.Shell.info() @@ -151,8 +156,8 @@ defmodule Mix.Tasks.Hex do keys = Hex.API.WebAuth.access_key(device_code) - write_key = keys["write_key"] - read_key = keys["read_key"] + write_key = keys.write_key + read_key = keys.read_key """ You have authenticated Hex using WebAuth. diff --git a/test/mix/tasks/hex.user_test.exs b/test/mix/tasks/hex.user_test.exs index c461401f..0e863f41 100644 --- a/test/mix/tasks/hex.user_test.exs +++ b/test/mix/tasks/hex.user_test.exs @@ -63,6 +63,63 @@ defmodule Mix.Tasks.Hex.UserTest do end) end + test "auth with --web" do + in_tmp(fn -> + set_home_cwd() + + task = Task.async(fn -> Mix.Tasks.Hex.User.run(["auth", "--web"]) end) + send(task.pid, {:mix_shell_input, :yes?, false}) + send(task.pid, {:mix_shell_input, :prompt, "hunter43"}) + send(task.pid, {:mix_shell_input, :prompt, "hunter43"}) + + # Wait for output to be sent + Process.sleep(100) + + task.pid + |> get_user_code + |> Hexpm.submit_web_auth_request(Hexpm.new_key(user: "user", pass: "hunter42")) + + Task.await(task) + + {:ok, name} = :inet.gethostname() + name = List.to_string(name) + + auth = Mix.Tasks.Hex.auth_info(:read) + assert {:ok, {200, body, _}} = Hex.API.Key.get(auth) + assert "#{name}-write-WebAuth" in Enum.map(body, & &1["name"]) + assert "#{name}-read-WebAuth" in Enum.map(body, & &1["name"]) + end) + end + + test "auth with --web --key-name" do + in_tmp(fn -> + set_home_cwd() + + task = + Task.async(fn -> + Mix.Tasks.Hex.User.run(["auth", "--web", "--key-name", "userauthkeyname"]) + end) + + send(task.pid, {:mix_shell_input, :yes?, false}) + send(task.pid, {:mix_shell_input, :prompt, "hunter43"}) + send(task.pid, {:mix_shell_input, :prompt, "hunter43"}) + + # Wait for output to be sent + Process.sleep(100) + + task.pid + |> get_user_code + |> Hexpm.submit_web_auth_request(Hexpm.new_key(user: "user", pass: "hunter42")) + + Task.await(task) + + auth = Mix.Tasks.Hex.auth_info(:read) + assert {:ok, {200, body, _}} = Hex.API.Key.get(auth) + assert "userauthkeyname-write-WebAuth" in Enum.map(body, & &1["name"]) + assert "userauthkeyname-read-WebAuth" in Enum.map(body, & &1["name"]) + end) + end + test "auth organizations" do in_tmp(fn -> set_home_cwd() @@ -239,4 +296,14 @@ defmodule Mix.Tasks.Hex.UserTest do assert_received {:mix_shell, :error, ["Wrong password. Try again"]} end) end + + defp get_user_code(pid) do + pid + |> Process.info(:messages) + |> elem(1) + |> Enum.at(2) + |> elem(2) + |> hd() + |> String.slice(31..39) + end end From 30ee7842ca12bf80b59662a03b24bad67a3e12c2 Mon Sep 17 00:00:00 2001 From: Benjamin Philip Date: Wed, 22 Dec 2021 17:32:05 +0530 Subject: [PATCH 05/13] Get submit url from WebAuth task --- lib/hex/api/web_auth.ex | 15 +++++---------- lib/mix/tasks/hex.ex | 2 +- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/lib/hex/api/web_auth.ex b/lib/hex/api/web_auth.ex index 657555c7..5f4eb77b 100644 --- a/lib/hex/api/web_auth.ex +++ b/lib/hex/api/web_auth.ex @@ -10,10 +10,10 @@ defmodule Hex.API.WebAuth do |> elem(1) end - def submit_in_browser() do + def submit_in_browser(url) do "Open link in browser?" |> Hex.Shell.yes?() - |> open() + |> open(url) end def access_key(device_code) do @@ -34,15 +34,10 @@ defmodule Hex.API.WebAuth do end end - defp open(bool) - defp open(false), do: :ok - - defp open(true) do - url = - :api_url - |> Hex.State.fetch!() - |> String.replace_suffix("api", "login/web_auth") + defp open(bool, url) + defp open(false, _), do: :ok + defp open(true, url) do {cmd, args} = case :os.type() do {:unix, :darwin} -> {"open", [url]} diff --git a/lib/mix/tasks/hex.ex b/lib/mix/tasks/hex.ex index 33b842e1..e82bd3c7 100644 --- a/lib/mix/tasks/hex.ex +++ b/lib/mix/tasks/hex.ex @@ -152,7 +152,7 @@ defmodule Mix.Tasks.Hex do |> Hex.Shell.format() |> Hex.Shell.info() - Hex.API.WebAuth.submit_in_browser() + Hex.API.WebAuth.submit_in_browser(submit_code_url) keys = Hex.API.WebAuth.access_key(device_code) From f8c77a4004373813429b997eaf7a0ac5e94dacd1 Mon Sep 17 00:00:00 2001 From: Benjamin Philip Date: Wed, 9 Feb 2022 13:54:32 +0530 Subject: [PATCH 06/13] Pattern match user and device codes in get_code --- lib/hex/api/web_auth.ex | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/hex/api/web_auth.ex b/lib/hex/api/web_auth.ex index 5f4eb77b..3abce92d 100644 --- a/lib/hex/api/web_auth.ex +++ b/lib/hex/api/web_auth.ex @@ -4,10 +4,10 @@ defmodule Hex.API.WebAuth do alias Hex.API def get_code(key_name) do - nil - |> API.erlang_post_request("web_auth/code", %{key_name: key_name}) - |> elem(1) - |> elem(1) + {:ok, {_status, code, _}} = + API.erlang_post_request(nil, "web_auth/code", %{key_name: key_name}) + + code end def submit_in_browser(url) do From c3f7119e57db7512f3a70034ec47a91485fbdb33 Mon Sep 17 00:00:00 2001 From: Benjamin Philip Date: Wed, 9 Feb 2022 13:56:54 +0530 Subject: [PATCH 07/13] Remove submit_in_browser function from Hex.API.WebAuth --- lib/hex/api/web_auth.ex | 20 -------------------- lib/hex/utils.ex | 11 +++++++++++ lib/mix/tasks/hex.ex | 4 +++- 3 files changed, 14 insertions(+), 21 deletions(-) diff --git a/lib/hex/api/web_auth.ex b/lib/hex/api/web_auth.ex index 3abce92d..16a8a385 100644 --- a/lib/hex/api/web_auth.ex +++ b/lib/hex/api/web_auth.ex @@ -10,12 +10,6 @@ defmodule Hex.API.WebAuth do code end - def submit_in_browser(url) do - "Open link in browser?" - |> Hex.Shell.yes?() - |> open(url) - end - def access_key(device_code) do Hex.API.check_write_api() @@ -33,18 +27,4 @@ defmodule Hex.API.WebAuth do access_key_task(params) end end - - defp open(bool, url) - defp open(false, _), do: :ok - - defp open(true, url) do - {cmd, args} = - case :os.type() do - {:unix, :darwin} -> {"open", [url]} - {:unix, _} -> {"xdg-open", [url]} - {:win32, _} -> {"cmd", ["/c", "start", url]} - end - - System.cmd(cmd, args) - end end diff --git a/lib/hex/utils.ex b/lib/hex/utils.ex index 89de5ba5..4d8735cc 100644 --- a/lib/hex/utils.ex +++ b/lib/hex/utils.ex @@ -320,4 +320,15 @@ defmodule Hex.Utils do {app, req, opts} end) end + + def open_url_in_browser(url) do + {cmd, args} = + case :os.type() do + {:unix, :darwin} -> {"open", [url]} + {:unix, _} -> {"xdg-open", [url]} + {:win32, _} -> {"cmd", ["/c", "start", url]} + end + + System.cmd(cmd, args) + end end diff --git a/lib/mix/tasks/hex.ex b/lib/mix/tasks/hex.ex index e82bd3c7..f08662a3 100644 --- a/lib/mix/tasks/hex.ex +++ b/lib/mix/tasks/hex.ex @@ -152,7 +152,9 @@ defmodule Mix.Tasks.Hex do |> Hex.Shell.format() |> Hex.Shell.info() - Hex.API.WebAuth.submit_in_browser(submit_code_url) + if Hex.Shell.yes?("Open link in browser?") do + Hex.Utils.open_url_in_browser(submit_code_url) + end keys = Hex.API.WebAuth.access_key(device_code) From 39432058afb0281afd16f2c163924f918c0e0341 Mon Sep 17 00:00:00 2001 From: Benjamin Philip Date: Wed, 9 Feb 2022 14:01:48 +0530 Subject: [PATCH 08/13] Improve task description --- lib/mix/tasks/hex.user.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mix/tasks/hex.user.ex b/lib/mix/tasks/hex.user.ex index b4f6446b..5ad76898 100644 --- a/lib/mix/tasks/hex.user.ex +++ b/lib/mix/tasks/hex.user.ex @@ -25,7 +25,7 @@ defmodule Mix.Tasks.Hex.User do * `--key-name KEY_NAME` - By default Hex will base the key name on your machine's hostname, use this option to give your own name. - * `--web` - Use WebAuth. + * `--web` - Use browser based authentication. ## Deauthorize the user From 2824fd5f787d65d964119a1e7ec300e26096ae4a Mon Sep 17 00:00:00 2001 From: Benjamin Philip Date: Wed, 9 Feb 2022 14:46:52 +0530 Subject: [PATCH 09/13] Pattern match user code in get_code --- test/mix/tasks/hex.user_test.exs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/test/mix/tasks/hex.user_test.exs b/test/mix/tasks/hex.user_test.exs index 0e863f41..c545a9cb 100644 --- a/test/mix/tasks/hex.user_test.exs +++ b/test/mix/tasks/hex.user_test.exs @@ -298,12 +298,10 @@ defmodule Mix.Tasks.Hex.UserTest do end defp get_user_code(pid) do - pid - |> Process.info(:messages) - |> elem(1) - |> Enum.at(2) - |> elem(2) - |> hd() - |> String.slice(31..39) + {:messages, [_, _, {:mix_shell, :info, [message]}, _]} = Process.info(pid, :messages) + + ["First copy your one-time code: " <> user_code, _, _] = String.split(message, "\n") + + user_code end end From fedb9514454f8476f3a1033e0176dc2d44a6edef Mon Sep 17 00:00:00 2001 From: Benjamin Philip Date: Wed, 9 Feb 2022 16:59:14 +0530 Subject: [PATCH 10/13] Sleep for 1 second between access key requests --- lib/hex/api/web_auth.ex | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/hex/api/web_auth.ex b/lib/hex/api/web_auth.ex index 16a8a385..a1d6e058 100644 --- a/lib/hex/api/web_auth.ex +++ b/lib/hex/api/web_auth.ex @@ -24,6 +24,7 @@ defmodule Hex.API.WebAuth do %{write_key: write_key, read_key: read_key} {:ok, {_code, %{"message" => "request to be verified"}, _headers}} -> + Process.sleep(1000) access_key_task(params) end end From 7dae6beb218e0de9a79601a45395f1fe73810600 Mon Sep 17 00:00:00 2001 From: Benjamin Philip Date: Wed, 9 Feb 2022 17:01:39 +0530 Subject: [PATCH 11/13] Revert "Sleep for 1 second between access key requests" This reverts commit fedb9514454f8476f3a1033e0176dc2d44a6edef. --- lib/hex/api/web_auth.ex | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/hex/api/web_auth.ex b/lib/hex/api/web_auth.ex index a1d6e058..16a8a385 100644 --- a/lib/hex/api/web_auth.ex +++ b/lib/hex/api/web_auth.ex @@ -24,7 +24,6 @@ defmodule Hex.API.WebAuth do %{write_key: write_key, read_key: read_key} {:ok, {_code, %{"message" => "request to be verified"}, _headers}} -> - Process.sleep(1000) access_key_task(params) end end From e9c73cfba50a047306e83c9307de684f918123c5 Mon Sep 17 00:00:00 2001 From: Benjamin Philip Date: Fri, 11 Feb 2022 15:18:55 +0530 Subject: [PATCH 12/13] Add timeout for fast access_key_task requests We don't want to try send an access_key request more than once per second. Therefore, this commit adds support for a timeout after a request, which will be used if a request completes in less than a second. --- lib/hex/api/web_auth.ex | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/hex/api/web_auth.ex b/lib/hex/api/web_auth.ex index 16a8a385..e1805eec 100644 --- a/lib/hex/api/web_auth.ex +++ b/lib/hex/api/web_auth.ex @@ -13,18 +13,24 @@ defmodule Hex.API.WebAuth do def access_key(device_code) do Hex.API.check_write_api() - fn -> access_key_task(%{device_code: device_code}) end + fn -> access_key_task(%{device_code: device_code}, DateTime.utc_now()) end |> Task.async() |> Task.await(5 * 60 * 1000) end - defp access_key_task(params) do + defp access_key_task(params, last_request_time) do case API.erlang_post_request(nil, "web_auth/access_key", params) do {:ok, {_code, %{"write_key" => write_key, "read_key" => read_key}, _headers}} -> %{write_key: write_key, read_key: read_key} {:ok, {_code, %{"message" => "request to be verified"}, _headers}} -> - access_key_task(params) + diff = DateTime.diff(DateTime.utc_now(), last_request_time) + + if diff < 1000 do + Process.sleep(1000 - diff) + end + + access_key_task(params, DateTime.utc_now()) end end end From 7ccbe7b6da4203e88e3e97a8edae5425f428ac92 Mon Sep 17 00:00:00 2001 From: Benjamin Philip Date: Sat, 12 Feb 2022 15:16:14 +0530 Subject: [PATCH 13/13] Use hand written timeout instead of Task.await to access_key --- lib/hex/api/web_auth.ex | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/hex/api/web_auth.ex b/lib/hex/api/web_auth.ex index e1805eec..51664a3b 100644 --- a/lib/hex/api/web_auth.ex +++ b/lib/hex/api/web_auth.ex @@ -13,24 +13,27 @@ defmodule Hex.API.WebAuth do def access_key(device_code) do Hex.API.check_write_api() - fn -> access_key_task(%{device_code: device_code}, DateTime.utc_now()) end - |> Task.async() - |> Task.await(5 * 60 * 1000) + now = System.os_time(:millisecond) + access_key(%{device_code: device_code}, now, now + 5 * 60 * 1000) end - defp access_key_task(params, last_request_time) do + defp access_key(params, last_request_time, timeout_time) do case API.erlang_post_request(nil, "web_auth/access_key", params) do {:ok, {_code, %{"write_key" => write_key, "read_key" => read_key}, _headers}} -> %{write_key: write_key, read_key: read_key} {:ok, {_code, %{"message" => "request to be verified"}, _headers}} -> - diff = DateTime.diff(DateTime.utc_now(), last_request_time) + diff = System.os_time(:millisecond) - last_request_time if diff < 1000 do Process.sleep(1000 - diff) end - access_key_task(params, DateTime.utc_now()) + access_key(params, System.os_time(:millisecond), timeout_time) end end + + defp access_key(_, last_request_time, timeout_time) when timeout_time > last_request_time do + raise "Browser-based authentication has timed out" + end end