From da2ca03a843011a4e45ef154d522a37e95a1deca Mon Sep 17 00:00:00 2001 From: Adrian Gruntkowski Date: Fri, 26 Apr 2024 10:02:50 +0200 Subject: [PATCH] Refactor `SiteController.google_auth_callback` --- lib/plausible/google/api.ex | 4 +- lib/plausible/google/http.ex | 17 +++- .../controllers/auth_controller.ex | 78 +++++++++++-------- 3 files changed, 61 insertions(+), 38 deletions(-) diff --git a/lib/plausible/google/api.ex b/lib/plausible/google/api.ex index 3e863c2f821a..50ec5d0ddda7 100644 --- a/lib/plausible/google/api.ex +++ b/lib/plausible/google/api.ex @@ -26,8 +26,8 @@ defmodule Plausible.Google.API do Jason.encode!([site_id, "import"]) end - def fetch_access_token!(code) do - HTTP.fetch_access_token!(code) + def fetch_access_token(code) do + HTTP.fetch_access_token(code) end def list_properties_and_views(access_token) do diff --git a/lib/plausible/google/http.ex b/lib/plausible/google/http.ex index be55fbcf5e54..43a9696a5235 100644 --- a/lib/plausible/google/http.ex +++ b/lib/plausible/google/http.ex @@ -22,7 +22,7 @@ defmodule Plausible.Google.HTTP do end end - def fetch_access_token!(code) do + def fetch_access_token(code) do url = "#{api_url()}/oauth2/v4/token" headers = [{"Content-Type", "application/x-www-form-urlencoded"}] @@ -34,9 +34,20 @@ defmodule Plausible.Google.HTTP do redirect_uri: redirect_uri() } - {:ok, response} = HTTPClient.post(url, headers, params) + case HTTPClient.impl().get(url, headers, params) do + {:ok, %{body: body}} -> + {:ok, body} + + {:error, %{reason: %{status: s}}} when s in [401, 403] -> + {:error, "google_auth_error"} - response.body + {:error, %{reason: %{body: %{"error" => error}}}} -> + {:error, error} + + {:error, reason} -> + Logger.error("Google Auth: failed to obtain access token: #{inspect(reason)}") + {:error, "failed_to_obtain_access_token"} + end end def list_stats(access_token, property, date_range, limit, page \\ nil) do diff --git a/lib/plausible_web/controllers/auth_controller.ex b/lib/plausible_web/controllers/auth_controller.ex index 1a526c09e1e8..c3ccb46ffc96 100644 --- a/lib/plausible_web/controllers/auth_controller.ex +++ b/lib/plausible_web/controllers/auth_controller.ex @@ -699,7 +699,7 @@ defmodule PlausibleWeb.AuthController do def google_auth_callback(conn, %{"error" => error, "state" => state} = params) do [site_id, redirected_to | _] = Jason.decode!(state) - site = Repo.get(Plausible.Site, site_id) + site = Repo.get!(Plausible.Site, site_id) redirect_route = if redirected_to == "import" do @@ -738,42 +738,54 @@ defmodule PlausibleWeb.AuthController do end def google_auth_callback(conn, %{"code" => code, "state" => state}) do - res = Plausible.Google.API.fetch_access_token!(code) - [site_id, redirect_to | _] = Jason.decode!(state) + site = Repo.get!(Plausible.Site, site_id) - site = Repo.get(Plausible.Site, site_id) - expires_at = NaiveDateTime.add(NaiveDateTime.utc_now(), res["expires_in"]) - - case redirect_to do - "import" -> - redirect(conn, - external: - Routes.google_analytics_path(conn, :property_or_view_form, site.domain, - access_token: res["access_token"], - refresh_token: res["refresh_token"], - expires_at: NaiveDateTime.to_iso8601(expires_at) - ) - ) + case Plausible.Google.API.fetch_access_token(code) do + {:ok, token_data} -> + %{"expires_in" => expires_in} = token_data + expires_at = NaiveDateTime.add(NaiveDateTime.utc_now(), expires_in) + google_auth_redirect(conn, site, redirect_to, token_data, expires_at) _ -> - id_token = res["id_token"] - [_, body, _] = String.split(id_token, ".") - id = body |> Base.decode64!(padding: false) |> Jason.decode!() - - Plausible.Site.GoogleAuth.changeset(%Plausible.Site.GoogleAuth{}, %{ - email: id["email"], - refresh_token: res["refresh_token"], - access_token: res["access_token"], - expires: expires_at, - user_id: conn.assigns[:current_user].id, - site_id: site_id - }) - |> Repo.insert!() - - site = Repo.get(Plausible.Site, site_id) - - redirect(conn, external: "/#{URI.encode_www_form(site.domain)}/settings/integrations") + conn + |> put_flash( + :error, + "We were unable to authenticate your Google Analytics account. Please try again in a few moments. If the problem persists, please contact support for assistance." + ) + |> redirect(external: Routes.site_path(conn, :settings_general, site.domain)) end end + + defp google_auth_redirect(conn, site, "import", token_data, expires_at) do + %{"access_token" => access_token, "refresh_token" => refresh_token} = token_data + + redirect(conn, + external: + Routes.google_analytics_path(conn, :property_or_view_form, site.domain, + access_token: access_token, + refresh_token: refresh_token, + expires_at: NaiveDateTime.to_iso8601(expires_at) + ) + ) + end + + defp google_auth_redirect(conn, site, _, token_data, expires_at) do + %{"access_token" => access_token, "refresh_token" => refresh_token} = token_data + %{"id_token" => id_token} = token_data + [_, body, _] = String.split(id_token, ".") + %{"email" => email} = body |> Base.decode64!(padding: false) |> Jason.decode!() + + Plausible.Site.GoogleAuth.changeset(%Plausible.Site.GoogleAuth{}, %{ + email: email, + refresh_token: refresh_token, + access_token: access_token, + expires: expires_at, + user_id: conn.assigns.current_user.id, + site_id: site.id + }) + |> Repo.insert!() + + redirect(conn, external: "/#{URI.encode_www_form(site.domain)}/settings/integrations") + end end