mirror of
https://github.com/plausible/analytics.git
synced 2024-11-23 03:04:43 +03:00
Add API key scopes
This commit is contained in:
parent
2fc136777c
commit
d473accf40
@ -5,6 +5,7 @@ defmodule Plausible.Auth.ApiKey do
|
||||
@required [:user_id, :key, :name]
|
||||
schema "api_keys" do
|
||||
field :name, :string
|
||||
field :scopes, {:array, :string}, default: ["stats:read:*"]
|
||||
|
||||
field :key, :string, virtual: true
|
||||
field :key_hash, :string
|
||||
|
@ -21,14 +21,20 @@ defmodule PlausibleWeb.AuthorizeSitesApiPlug do
|
||||
{:error, :invalid_api_key} ->
|
||||
unauthorized(
|
||||
conn,
|
||||
"Invalid API key. Please make sure you're using a valid API key with access to the site you've requested."
|
||||
"Invalid API key. Please make sure you're using a valid API key with access to the resource you've requested."
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
defp verify_access(api_key) do
|
||||
hashed_key = ApiKey.do_hash(api_key)
|
||||
found_key = Repo.get_by(ApiKey, key_hash: hashed_key)
|
||||
|
||||
found_key =
|
||||
Repo.one(
|
||||
from a in ApiKey,
|
||||
where: a.key_hash == ^hashed_key,
|
||||
where: fragment("? @> ?", a.scopes, ["sites:provision:*"])
|
||||
)
|
||||
|
||||
cond do
|
||||
found_key -> {:ok, found_key}
|
||||
|
24
priv/repo/migrations/20210409082603_add_api_key_scopes.exs
Normal file
24
priv/repo/migrations/20210409082603_add_api_key_scopes.exs
Normal file
@ -0,0 +1,24 @@
|
||||
defmodule Plausible.Repo.Migrations.AddApiKeyScopes do
|
||||
use Ecto.Migration
|
||||
|
||||
def up do
|
||||
alter table(:api_keys) do
|
||||
add :scopes, {:array, :text}
|
||||
end
|
||||
|
||||
execute "UPDATE api_keys SET scopes='{stats:read:*}'"
|
||||
|
||||
alter table(:api_keys) do
|
||||
modify :scopes, {:array, :text}, null: false
|
||||
end
|
||||
|
||||
# https://stackoverflow.com/a/4059785
|
||||
create index(:api_keys, [:scopes], using: "GIN")
|
||||
end
|
||||
|
||||
def down do
|
||||
alter table(:api_keys) do
|
||||
remove :scopes
|
||||
end
|
||||
end
|
||||
end
|
@ -2,7 +2,12 @@ defmodule PlausibleWeb.Api.ExternalSitesControllerTest do
|
||||
use PlausibleWeb.ConnCase
|
||||
import Plausible.TestUtils
|
||||
|
||||
setup [:create_user, :create_api_key, :use_api_key]
|
||||
setup %{conn: conn} do
|
||||
user = insert(:user)
|
||||
api_key = insert(:api_key, user: user, scopes: ["sites:provision:*"])
|
||||
conn = Plug.Conn.put_req_header(conn, "authorization", "Bearer #{api_key.key}")
|
||||
{:ok, user: user, api_key: api_key, conn: conn}
|
||||
end
|
||||
|
||||
describe "POST /api/v1/sites" do
|
||||
test "can create a site", %{conn: conn} do
|
||||
@ -41,6 +46,20 @@ defmodule PlausibleWeb.Api.ExternalSitesControllerTest do
|
||||
"error" => "domain can't be blank"
|
||||
}
|
||||
end
|
||||
|
||||
test "cannot access with a bad API key scope", %{conn: conn, user: user} do
|
||||
api_key = insert(:api_key, user: user, scopes: ["stats:read:*"])
|
||||
|
||||
conn =
|
||||
conn
|
||||
|> Plug.Conn.put_req_header("authorization", "Bearer #{api_key.key}")
|
||||
|> post("/api/v1/sites", %{"site" => %{"domain" => "domain.com"}})
|
||||
|
||||
assert json_response(conn, 401) == %{
|
||||
"error" =>
|
||||
"Invalid API key. Please make sure you're using a valid API key with access to the resource you've requested."
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
describe "PUT /api/v1/sites/shared-links/:link_name" do
|
||||
|
Loading…
Reference in New Issue
Block a user