Skip to content

Commit

Permalink
Space credential validity check
Browse files Browse the repository at this point in the history
  • Loading branch information
zacksiri committed Feb 21, 2024
1 parent e505403 commit d119651
Show file tree
Hide file tree
Showing 10 changed files with 198 additions and 3 deletions.
4 changes: 4 additions & 0 deletions lib/polar/accounts.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ defmodule Polar.Accounts do
to: Space.Manager,
as: :create_credential

defdelegate space_credential_valid?(credential),
to: Space.Manager,
as: :credential_valid?

alias Polar.Accounts.Automation

defdelegate generate_automation_password,
Expand Down
5 changes: 5 additions & 0 deletions lib/polar/accounts/automation.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
defmodule Polar.Accounts.Automation do
alias Polar.Repo
alias Polar.Accounts

@email "[email protected]"
Expand All @@ -11,6 +12,10 @@ defmodule Polar.Accounts.Automation do
|> String.downcase()
end

def get_bot! do
Repo.get_by!(Accounts.User, email: @email)
end

def create_bot(password) do
with {:ok, user} <-
Accounts.register_user(%{
Expand Down
6 changes: 6 additions & 0 deletions lib/polar/accounts/space/credential.ex
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ defmodule Polar.Accounts.Space.Credential do
Transitions
|> governs(:current_state, on: Event)

import Ecto.Query, only: [from: 2]

@expires_in_range [
%{label: "15", value: 1_296_000},
%{label: "30", value: 2_592_000},
Expand Down Expand Up @@ -50,6 +52,10 @@ defmodule Polar.Accounts.Space.Credential do
|> validate_required([:token, :type, :name])
end

def scope(:active, queryable) do
from(c in queryable, where: c.current_state == "active")
end

defp maybe_set_expires_at(changeset) do
if expires_in = get_change(changeset, :expires_in) do
expires_at =
Expand Down
6 changes: 6 additions & 0 deletions lib/polar/accounts/space/credential/transitions.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ defmodule Polar.Accounts.Space.Credential.Transitions do
fn changes -> transit(changes) end
)

Credential
|> transition(
[from: "active", to: "expired", via: "expire"],
fn changes -> transit(changes) end
)

Credential
|> transition(
[from: "active", to: "deleted", via: "delete"],
Expand Down
17 changes: 16 additions & 1 deletion lib/polar/accounts/space/manager.ex
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ defmodule Polar.Accounts.Space.Manager do
end

def get_credential(token: token) do
Repo.get_by(Space.Credential, token: token)
Space.Credential.scope(:active, Space.Credential)
|> Repo.get_by(token: token)
end

def create_credential(%Accounts.Space{} = space, user, params) do
Expand All @@ -31,6 +32,20 @@ defmodule Polar.Accounts.Space.Manager do
end
end

def credential_valid?(nil), do: false

def credential_valid?(%Space.Credential{expires_at: expires_at} = credential) do
if is_nil(expires_at) || DateTime.compare(expires_at, DateTime.utc_now()) == :gt do
true
else
bot = Accounts.Automation.get_bot!()

Eventful.Transit.perform(credential, bot, "expire")

false
end
end

def increment_credential_access(%Space.Credential{id: credential_id}) do
from(
c in Accounts.Space.Credential,
Expand Down
4 changes: 3 additions & 1 deletion lib/polar_web/controllers/streams/item_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ defmodule PolarWeb.Streams.ItemController do
alias Polar.Accounts
alias Polar.Streams.Item

action_fallback PolarWeb.FallbackController

def show(conn, %{"space_token" => space_token, "id" => id}) do
credential =
Accounts.get_space_credential(token: space_token)
|> Repo.preload([:space])

if credential do
if Accounts.space_credential_valid?(credential) do
%{
default_cdn_host: default_cdn_host
} = Polar.Assets.config()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
defmodule Polar.Repo.Migrations.AddUniqueIndexForSpaceCredentials do
use Ecto.Migration

def change do
create index(:space_credentials, [:token], unique: true)
end
end
43 changes: 43 additions & 0 deletions test/polar/accounts/space/manager_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ defmodule Polar.Accounts.Space.ManagerTest do

import Polar.AccountsFixtures

alias Polar.Repo
alias Polar.Accounts

setup do
Expand Down Expand Up @@ -35,4 +36,46 @@ defmodule Polar.Accounts.Space.ManagerTest do
assert byte_size(credential.token) == 24
end
end

describe "credential_valid?" do
setup %{user: user} do
password = Accounts.generate_automation_password()

_bot = bot_fixture(%{password: password})

{:ok, space} = Accounts.create_space(user, %{name: "test-validity"})

{:ok, credential} =
Accounts.create_space_credential(space, user, %{
expires_in: 1_296_000,
name: "test",
type: "lxd"
})

{:ok, credential: credential}
end

test "is valid", %{credential: credential} do
assert Accounts.space_credential_valid?(credential)
end

test "not valid", %{credential: credential} do
changeset =
Ecto.Changeset.cast(
credential,
%{
expires_at: DateTime.add(DateTime.utc_now(), -1_297_000)
},
[:expires_at]
)

{:ok, credential} = Repo.update(changeset)

refute Accounts.space_credential_valid?(credential)

credential = Repo.reload(credential)

assert credential.current_state == "expired"
end
end
end
107 changes: 107 additions & 0 deletions test/polar_web/controllers/streams/item_controller_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
defmodule PolarWeb.Streams.ItemControllerTest do
use PolarWeb.ConnCase

alias Polar.Repo
alias Polar.Accounts
alias Polar.Streams
alias Polar.Streams.Product

import Polar.AccountsFixtures

setup do
user = user_fixture()

password = Accounts.generate_automation_password()

_bot = bot_fixture(%{password: password})

{:ok, space} = Accounts.create_space(user, %{name: "some-test-item"})

{:ok, %Product{} = product} =
Streams.create_product(%{
aliases: ["alpine/3.18", "alpine/3.18/default"],
arch: "amd64",
os: "Alpine",
release: "3.19",
release_title: "3.19",
variant: "default",
requirements: %{
secureboot: false
}
})

{:ok, version} =
Streams.create_version(product, %{
serial: "20240209_13:00",
items: [
%{
name: "lxd.tar.gz",
file_type: "lxd.tar.gz",
hash: "35363f3d086271ed5402d61ab18ec03987bed51758c00079b8c9d372ff6d62dd",
size: 876,
path: "images/alpine/edge/amd64/default/20240209_13:00/incus.tar.xz"
},
%{
name: "root.squashfs",
file_type: "squashfs",
hash: "47cc4070da1bf17d8364c390…3603f4ed7e9e46582e690d2",
size: 2_982_800,
path: "images/alpine/edge/amd64/default/20240209_13:00/rootfs.tar.xz"
}
]
})

item = List.first(version.items)

{:ok, space: space, user: user, item: item}
end

describe "valid credential" do
setup %{space: space, user: user} do
{:ok, credential} =
Accounts.create_space_credential(space, user, %{
expires_in: 1_296_000,
name: "test-02",
type: "lxd"
})

{:ok, credential: credential}
end

test "GET /spaces/:space_token/items/:id", %{credential: credential, item: item} do
conn = get(build_conn(), ~s"/spaces/#{credential.token}/items/#{item.id}")

assert response(conn, 302)
end
end

describe "invalid credential" do
setup %{space: space, user: user} do
{:ok, credential} =
Accounts.create_space_credential(space, user, %{
expires_in: 1_296_000,
name: "test-02",
type: "lxd"
})

changeset =
Ecto.Changeset.cast(
credential,
%{
expires_at: DateTime.add(DateTime.utc_now(), -1_297_000)
},
[:expires_at]
)

{:ok, credential} = Repo.update(changeset)

{:ok, credential: credential}
end

test "GET /spaces/:space_token/items/:id", %{credential: credential, item: item} do
conn = get(build_conn(), ~s"/spaces/#{credential.token}/items/#{item.id}")

assert response(conn, 404)
end
end
end
2 changes: 1 addition & 1 deletion test/support/fixtures/accounts_fixtures.ex
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ defmodule Polar.AccountsFixtures do
user
end

def bot_fixture(attrs \\ %{}) do
def bot_fixture(attrs \\ %{password: "somepassword"}) do
{:ok, bot} = Automation.create_bot(attrs.password)

bot
Expand Down

0 comments on commit d119651

Please sign in to comment.