Some checks failed
Build and Push / Build and Push Docker Image (push) Failing after 2s
- Content-Security-Policy: nonce-based per-request plug replacing unsafe-inline scripts - RemoteIp: CIDR-based trust gating via InetCidr, skips forwarded headers from untrusted peers - Rate limiting: auth pipeline (20/min), LiveView event handlers, existing mobile channel limits - NetworkPolicy: 4 k8s policies (web ingress, cluster, metrics, egress) for least-privilege networking - PartitionManager: deadlock retry with exponential backoff in drop_partition - Tests: reduced parallelism (max_cases 4), packets_test async:false to prevent trigger contention - k8s: APRS_PASSWORD -> APRS_PASSCODE secretRef, vendor/aprs submodule hardened
125 lines
4 KiB
Elixir
125 lines
4 KiB
Elixir
defmodule AprsmeWeb.UserSessionControllerTest do
|
|
use AprsmeWeb.ConnCase
|
|
|
|
import Aprsme.AccountsFixtures
|
|
|
|
setup do
|
|
# Reset the shared Hammer ETS table so rate-limit counts don't bleed between tests
|
|
case :ets.info(Aprsme.RateLimiter) do
|
|
:undefined -> :ok
|
|
_ -> :ets.delete_all_objects(Aprsme.RateLimiter)
|
|
end
|
|
|
|
%{user: user_fixture()}
|
|
end
|
|
|
|
describe "POST /users/log_in" do
|
|
test "logs the user in", %{conn: conn, user: user} do
|
|
conn =
|
|
post(conn, ~p"/users/log_in", %{
|
|
"user" => %{"email" => user.email, "password" => valid_user_password()}
|
|
})
|
|
|
|
assert get_session(conn, :user_token)
|
|
assert redirected_to(conn) == ~p"/"
|
|
end
|
|
|
|
test "logs the user in with remember me", %{conn: conn, user: user} do
|
|
conn =
|
|
post(conn, ~p"/users/log_in", %{
|
|
"user" => %{
|
|
"email" => user.email,
|
|
"password" => valid_user_password(),
|
|
"remember_me" => "true"
|
|
}
|
|
})
|
|
|
|
assert conn.resp_cookies["_aprs_web_user_remember_me"]
|
|
assert redirected_to(conn) == ~p"/"
|
|
end
|
|
|
|
test "logs the user in with return to", %{conn: conn, user: user} do
|
|
conn =
|
|
conn
|
|
|> init_test_session(user_return_to: "/foo/bar")
|
|
|> post(~p"/users/log_in", %{
|
|
"user" => %{
|
|
"email" => user.email,
|
|
"password" => valid_user_password()
|
|
}
|
|
})
|
|
|
|
assert redirected_to(conn) == "/foo/bar"
|
|
assert Phoenix.Flash.get(conn.assigns.flash, :info) =~ "Welcome back!"
|
|
end
|
|
|
|
test "login following registration", %{conn: conn, user: user} do
|
|
conn =
|
|
post(conn, ~p"/users/log_in", %{
|
|
"_action" => "registered",
|
|
"user" => %{
|
|
"email" => user.email,
|
|
"password" => valid_user_password()
|
|
}
|
|
})
|
|
|
|
assert redirected_to(conn) == ~p"/"
|
|
assert Phoenix.Flash.get(conn.assigns.flash, :info) =~ "Account created successfully!"
|
|
end
|
|
|
|
test "login following password update", %{conn: conn, user: user} do
|
|
conn =
|
|
conn
|
|
|> init_test_session(%{})
|
|
|> post(~p"/users/log_in", %{
|
|
"_action" => "password_updated",
|
|
"user" => %{
|
|
"email" => user.email,
|
|
"password" => valid_user_password()
|
|
}
|
|
})
|
|
|
|
assert redirected_to(conn) == ~p"/users/settings"
|
|
assert Phoenix.Flash.get(conn.assigns.flash, :info) =~ "Password updated successfully!"
|
|
end
|
|
|
|
test "redirects to login page with invalid credentials", %{conn: conn, user: user} do
|
|
conn =
|
|
post(conn, ~p"/users/log_in", %{
|
|
"user" => %{"email" => user.email, "password" => "invalid_password"}
|
|
})
|
|
|
|
assert Phoenix.Flash.get(conn.assigns.flash, :error) == "Invalid email or password"
|
|
assert redirected_to(conn) == ~p"/users/log_in"
|
|
end
|
|
end
|
|
|
|
describe "DELETE /users/log_out" do
|
|
test "logs the user out", %{conn: conn, user: user} do
|
|
conn = conn |> log_in_user(user) |> delete(~p"/users/log_out")
|
|
assert redirected_to(conn) == ~p"/"
|
|
refute get_session(conn, :user_token)
|
|
assert Phoenix.Flash.get(conn.assigns.flash, :info) =~ "Logged out successfully"
|
|
end
|
|
|
|
test "succeeds even if the user is not logged in", %{conn: conn} do
|
|
conn = delete(conn, ~p"/users/log_out")
|
|
assert redirected_to(conn) == ~p"/"
|
|
refute get_session(conn, :user_token)
|
|
assert Phoenix.Flash.get(conn.assigns.flash, :info) =~ "Logged out successfully"
|
|
end
|
|
end
|
|
|
|
describe "end-to-end rate limit on auth route" do
|
|
test "POST /users/log_in returns 429 after exceeding auth rate limit", %{conn: conn, user: user} do
|
|
# The :auth pipeline limits to 20 requests per minute with prefix "auth_rate_limit"
|
|
results =
|
|
Enum.map(1..25, fn _i ->
|
|
post(conn, ~p"/users/log_in", %{"user" => %{"email" => user.email, "password" => "wrong_password"}})
|
|
end)
|
|
|
|
# At least one of the later requests should return 429
|
|
assert Enum.any?(results, &(&1.status == 429))
|
|
end
|
|
end
|
|
end
|