Skip to content

Commit

Permalink
Revert "Implement token-based sessions (#4463)"
Browse files Browse the repository at this point in the history
This reverts commit 373d4dd.
  • Loading branch information
zoldar committed Sep 3, 2024
1 parent 373d4dd commit ff71e21
Show file tree
Hide file tree
Showing 33 changed files with 364 additions and 879 deletions.
1 change: 0 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ All notable changes to this project will be documented in this file.
- Make `TOTP_VAULT_KEY` optional plausible/analytics#4317
- Sources like 'google' and 'facebook' are now stored in capitalized forms ('Google', 'Facebook') plausible/analytics#4417
- `DATABASE_CACERTFILE` now forces TLS for PostgreSQL connections, so you don't need to add `?ssl=true` in `DATABASE_URL`
- Change auth session cookies to token-based ones with server-side expiration management.

### Fixed

Expand Down
3 changes: 0 additions & 3 deletions config/runtime.exs
Original file line number Diff line number Diff line change
Expand Up @@ -587,8 +587,6 @@ base_cron = [
# Every day at 1am
{"0 1 * * *", Plausible.Workers.CleanInvitations},
# Every 2 hours
{"30 */2 * * *", Plausible.Workers.CleanUserSessions},
# Every 2 hours
{"0 */2 * * *", Plausible.Workers.ExpireDomainChangeTransitions},
# Daily at midnight
{"0 0 * * *", Plausible.Workers.LocationsSync}
Expand Down Expand Up @@ -619,7 +617,6 @@ base_queues = [
check_stats_emails: 1,
site_setup_emails: 1,
clean_invitations: 1,
clean_user_sessions: 1,
analytics_imports: 1,
analytics_exports: 1,
notify_exported_analytics: 1,
Expand Down
1 change: 0 additions & 1 deletion lib/plausible/auth/user.ex
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ defmodule Plausible.Auth.User do

embeds_one :grace_period, Plausible.Auth.GracePeriod, on_replace: :update

has_many :sessions, Plausible.Auth.UserSession
has_many :site_memberships, Plausible.Site.Membership
has_many :sites, through: [:site_memberships, :site]
has_many :api_keys, Plausible.Auth.ApiKey
Expand Down
43 changes: 2 additions & 41 deletions lib/plausible/auth/user_session.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,48 +5,9 @@ defmodule Plausible.Auth.UserSession do

use Ecto.Schema

import Ecto.Changeset

alias Plausible.Auth

@type t() :: %__MODULE__{}

@rand_size 32
@timeout Duration.new!(day: 14)

schema "user_sessions" do
field :token, :binary
field :device, :string
field :last_used_at, :naive_datetime
field :timeout_at, :naive_datetime

belongs_to :user, Plausible.Auth.User

timestamps(updated_at: false)
end

@spec timeout_duration() :: Duration.t()
def timeout_duration(), do: @timeout

@spec new_session(Auth.User.t(), String.t(), NaiveDateTime.t()) :: Ecto.Changeset.t()
def new_session(user, device, now \\ NaiveDateTime.utc_now(:second)) do
%__MODULE__{}
|> cast(%{device: device}, [:device])
|> generate_token()
|> put_assoc(:user, user)
|> touch_session(now)
end

@spec touch_session(t() | Ecto.Changeset.t(), NaiveDateTime.t()) :: Ecto.Changeset.t()
def touch_session(session, now \\ NaiveDateTime.utc_now(:second)) do
session
|> change()
|> put_change(:last_used_at, now)
|> put_change(:timeout_at, NaiveDateTime.shift(now, @timeout))
end

defp generate_token(changeset) do
token = :crypto.strong_rand_bytes(@rand_size)
put_change(changeset, :token, token)
embedded_schema do
field :user_id, :integer
end
end
35 changes: 9 additions & 26 deletions lib/plausible/users.ex
Original file line number Diff line number Diff line change
Expand Up @@ -35,19 +35,6 @@ defmodule Plausible.Users do
|> Repo.update!()
end

@spec bump_last_seen(Auth.User.t() | pos_integer(), NaiveDateTime.t()) :: :ok
def bump_last_seen(%Auth.User{id: user_id}, now) do
bump_last_seen(user_id, now)
end

def bump_last_seen(user_id, now) do
q = from(u in Auth.User, where: u.id == ^user_id)

Repo.update_all(q, set: [last_seen: now])

:ok
end

@spec accept_traffic_until(Auth.User.t()) :: Date.t()
on_ee do
def accept_traffic_until(user) do
Expand Down Expand Up @@ -77,18 +64,19 @@ defmodule Plausible.Users do
end
end

def with_subscription(%Auth.User{} = user) do
Repo.preload(user, subscription: last_subscription_query())
def with_subscription(%Auth.User{id: user_id} = user) do
Repo.preload(user, subscription: last_subscription_query(user_id))
end

def with_subscription(user_id) when is_integer(user_id) do
Repo.one(
from(user in Auth.User,
as: :user,
left_lateral_join: s in subquery(last_subscription_join_query()),
on: true,
left_join: last_subscription in subquery(last_subscription_query(user_id)),
on: last_subscription.user_id == user.id,
left_join: subscription in Subscription,
on: subscription.id == last_subscription.id,
where: user.id == ^user_id,
preload: [subscription: s]
preload: [subscription: subscription]
)
)
end
Expand All @@ -114,14 +102,9 @@ defmodule Plausible.Users do
end
end

def last_subscription_join_query() do
from(subscription in last_subscription_query(),
where: subscription.user_id == parent_as(:user).id
)
end

defp last_subscription_query() do
defp last_subscription_query(user_id) do
from(subscription in Subscription,
where: subscription.user_id == ^user_id,
order_by: [desc: subscription.inserted_at],
limit: 1
)
Expand Down
4 changes: 2 additions & 2 deletions lib/plausible_web.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ defmodule PlausibleWeb do
use Phoenix.LiveView, global_prefixes: ~w(x-)
use PlausibleWeb.Live.Flash

use PlausibleWeb.Live.AuthContext

unless :no_sentry_context in unquote(opts) do
use PlausibleWeb.Live.SentryContext
end

use PlausibleWeb.Live.AuthContext

alias PlausibleWeb.Router.Helpers, as: Routes
alias Phoenix.LiveView.JS
end
Expand Down
6 changes: 4 additions & 2 deletions lib/plausible_web/live/auth_context.ex
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@ defmodule PlausibleWeb.Live.AuthContext do
end
end)
|> assign_new(:current_user, fn context ->
case context.current_user_session do
%{user: user} -> user
with %{} = user_session <- context.current_user_session,
{:ok, user} <- UserAuth.get_user(user_session) do
user
else
_ -> nil
end
end)
Expand Down
14 changes: 9 additions & 5 deletions lib/plausible_web/live/sentry_context.ex
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ defmodule PlausibleWeb.Live.SentryContext do
end
end

def on_mount(:default, _params, _session, socket) do
def on_mount(:default, _params, session, socket) do
if Phoenix.LiveView.connected?(socket) do
peer = Phoenix.LiveView.get_connect_info(socket, :peer_data)
uri = Phoenix.LiveView.get_connect_info(socket, :uri)
Expand Down Expand Up @@ -49,10 +49,14 @@ defmodule PlausibleWeb.Live.SentryContext do

Sentry.Context.set_request_context(request_context)

if current_user = socket.assigns[:current_user] do
Sentry.Context.set_user_context(%{
id: current_user.id
})
case PlausibleWeb.UserAuth.get_user_session(session) do
{:ok, user_session} ->
Sentry.Context.set_user_context(%{
id: user_session.user_id
})

_ ->
:pass
end
end

Expand Down
20 changes: 9 additions & 11 deletions lib/plausible_web/plugs/auth_plug.ex
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,15 @@ defmodule PlausibleWeb.AuthPlug do
end

def call(conn, _opts) do
case UserAuth.get_user_session(conn) do
{:ok, user_session} ->
user = user_session.user

Plausible.OpenTelemetry.add_user_attributes(user)
Sentry.Context.set_user_context(%{id: user.id, name: user.name, email: user.email})

conn
|> assign(:current_user, user)
|> assign(:current_user_session, user_session)

with {:ok, user_session} <- UserAuth.get_user_session(conn),
{:ok, user} <- UserAuth.get_user(user_session) do
Plausible.OpenTelemetry.add_user_attributes(user)
Sentry.Context.set_user_context(%{id: user.id, name: user.name, email: user.email})

conn
|> assign(:current_user, user)
|> assign(:current_user_session, user_session)
else
_ ->
conn
end
Expand Down
37 changes: 37 additions & 0 deletions lib/plausible_web/plugs/last_seen_plug.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
defmodule PlausibleWeb.LastSeenPlug do
import Plug.Conn
use Plausible.Repo

@one_hour 60 * 60

def init(opts) do
opts
end

def call(conn, _opts) do
last_seen = get_session(conn, :last_seen)
user = conn.assigns[:current_user]

cond do
user && last_seen && last_seen < unix_now() - @one_hour ->
persist_last_seen(user)
put_session(conn, :last_seen, unix_now())

user && !last_seen ->
put_session(conn, :last_seen, unix_now())

true ->
conn
end
end

defp persist_last_seen(user) do
q = from(u in Plausible.Auth.User, where: u.id == ^user.id)

Repo.update_all(q, set: [last_seen: DateTime.utc_now()])
end

defp unix_now do
DateTime.utc_now() |> DateTime.to_unix()
end
end
13 changes: 9 additions & 4 deletions lib/plausible_web/plugs/session_timeout_plug.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,24 @@ defmodule PlausibleWeb.SessionTimeoutPlug do
"""
import Plug.Conn

alias PlausibleWeb.UserAuth

def init(opts \\ []) do
opts
end

def call(conn, opts) do
timeout_at = get_session(conn, :session_timeout_at)
user_id = get_session(conn, :current_user_id)

user_id =
case UserAuth.get_user_session(conn) do
{:ok, session} -> session.user_id
_ -> nil
end

cond do
user_id && timeout_at && now() > timeout_at ->
conn
|> PlausibleWeb.UserAuth.log_out_user()
|> halt()
PlausibleWeb.UserAuth.log_out_user(conn)

user_id ->
put_session(
Expand Down
16 changes: 6 additions & 10 deletions lib/plausible_web/plugs/super_admin_only_plug.ex
Original file line number Diff line number Diff line change
@@ -1,24 +1,20 @@
defmodule PlausibleWeb.SuperAdminOnlyPlug do
@moduledoc false

use Plausible.Repo

import Plug.Conn
use Plausible.Repo

def init(options) do
options
end

def call(conn, _opts) do
current_user = conn.assigns[:current_user]

if current_user && Plausible.Auth.is_super_admin?(current_user) do
conn
with {:ok, user} <- PlausibleWeb.UserAuth.get_user(conn),
true <- Plausible.Auth.is_super_admin?(user) do
assign(conn, :current_user, user)
else
conn
|> PlausibleWeb.UserAuth.log_out_user()
|> send_resp(403, "Not allowed")
|> halt()
_ ->
conn |> send_resp(403, "Not allowed") |> halt
end
end
end
28 changes: 0 additions & 28 deletions lib/plausible_web/plugs/user_session_touch.ex

This file was deleted.

Loading

0 comments on commit ff71e21

Please sign in to comment.