No longer require domain to seek Plugins API Tokens (#3409)

* No longer require domain to seek Plugins API Tokens

* Accept raw token only
This commit is contained in:
hq1 2023-10-16 13:22:09 +02:00 committed by GitHub
parent 70c001099d
commit 99efb93082
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 35 additions and 29 deletions

View File

@ -18,15 +18,14 @@ defmodule Plausible.Plugins.API.Tokens do
end
end
@spec find(String.t(), String.t()) :: {:ok, Token.t()} | {:error, :not_found}
def find(domain, raw) do
@spec find(String.t()) :: {:ok, Token.t()} | {:error, :not_found}
def find(raw) do
found =
Repo.one(
from(t in Token,
inner_join: s in Site,
on: s.id == t.site_id,
where: t.token_hash == ^Token.hash(raw),
where: s.domain == ^domain or s.domain_changed_from == ^domain,
preload: [:site]
)
)

View File

@ -28,8 +28,9 @@ defmodule PlausibleWeb.Plugins.API.Spec do
type: "http",
scheme: "basic",
description: """
HTTP basic access authentication using your Site domain as the
HTTP basic access authentication using your Site Domain as the
username and the Plugins API Token contents as the password.
Note that Site Domain is optional, a password alone suffices.
For more information see
https://en.wikipedia.org/wiki/Basic_access_authentication

View File

@ -6,18 +6,19 @@ defmodule PlausibleWeb.Plugs.AuthorizePluginsAPI do
alias PlausibleWeb.Plugins.API.Errors
alias Plausible.Plugins.API.Tokens
import Plug.Conn
def init(opts), do: opts
def call(conn, _opts \\ []) do
with {:ok, domain, token} <- extract_token(conn),
{:ok, conn} <- authorize(conn, domain, token) do
with {:ok, token} <- extract_token(conn),
{:ok, conn} <- authorize(conn, token) do
conn
end
end
defp authorize(conn, domain, token_value) do
case Tokens.find(domain, token_value) do
defp authorize(conn, token_value) do
case Tokens.find(token_value) do
{:ok, token} ->
{:ok, Plug.Conn.assign(conn, :authorized_site, token.site)}
@ -27,11 +28,14 @@ defmodule PlausibleWeb.Plugs.AuthorizePluginsAPI do
end
defp extract_token(conn) do
case Plug.BasicAuth.parse_basic_auth(conn) do
{token_identifier, token_value} ->
{:ok, token_identifier, token_value}
:error ->
with ["Basic " <> encoded_user_and_pass] <- get_req_header(conn, "authorization"),
{:ok, decoded_user_and_pass} <- Base.decode64(encoded_user_and_pass) do
case :binary.split(decoded_user_and_pass, ":") do
[_user, token_value] -> {:ok, token_value}
[token_value] -> {:ok, token_value}
end
else
_ ->
Errors.unauthorized(conn)
end
end

View File

@ -31,26 +31,13 @@ defmodule Plausible.Plugins.API.TokensTest do
test "finds the right token" do
site = insert(:site)
assert {:ok, _, raw} = Tokens.create(site, "My test token")
assert {:ok, found} = Tokens.find(site.domain, raw)
assert {:ok, found} = Tokens.find(raw)
assert found.id == found.id
end
test "finds the right token after domain change" do
site = insert(:site, domain: "foo1.example.com")
assert {:ok, _, raw} = Tokens.create(site, "My test token")
{:ok, _} = Plausible.Site.Domain.change(site, "foo2.example.com")
assert {:ok, found} = Tokens.find("foo1.example.com", raw)
assert {:ok, ^found} = Tokens.find("foo2.example.com", raw)
assert found.site_id == site.id
end
test "fails to find the token" do
site = insert(:site)
assert {:ok, _, _} = Tokens.create(site, "My test token")
assert {:error, :not_found} = Tokens.find(site.domain, "non-existing")
assert {:error, :not_found} = Tokens.find("non-existing", "non-existing")
assert {:error, :not_found} = Tokens.find("non-existing")
end
end
end

View File

@ -21,6 +21,21 @@ defmodule PlausibleWeb.Plugs.AuthorizePluginsAPITest do
assert %Plausible.Site{id: ^site_id} = conn.assigns.authorized_site
end
test "plug passes when a token is found, no domain provided" do
%{id: site_id} = site = insert(:site, domain: "pass.example.com")
{:ok, _, raw} = Tokens.create(site, "Some token")
credentials = "Basic " <> Base.encode64(raw)
conn =
build_conn()
|> put_req_header("authorization", credentials)
|> AuthorizePluginsAPI.call()
refute conn.halted
assert %Plausible.Site{id: ^site_id} = conn.assigns.authorized_site
end
test "plug halts when a token is not found" do
site = insert(:site, domain: "pass.example.com")