Skip to content

Commit

Permalink
Merge pull request #1559 from GSA/dev-merge-2025-02-09
Browse files Browse the repository at this point in the history
merge staging into dev 2025 02 09
  • Loading branch information
kkrug authored Feb 10, 2025
2 parents 299cd89 + 7670388 commit ccc6a0c
Show file tree
Hide file tree
Showing 18 changed files with 97 additions and 158 deletions.
Binary file removed .DS_Store
Binary file not shown.
2 changes: 1 addition & 1 deletion assets/client/src/components/ChallengeDetails.js
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ export const ChallengeDetails = ({challenge, challengePhases, preview, print, ta
<div className="logos">
<img
className="agency-logo"
src={`${imageBase}${encodeURIComponent(challenge.agency_logo)}`}
src={`${imageBase && imageBase !== 'null' ? imageBase : ''}${challenge.agency_logo || ''}`}
alt={`Agency logo for ${challenge.agency_name}`}
/>

Expand Down
2 changes: 1 addition & 1 deletion assets/client/src/components/ChallengeTab.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export const ChallengeTab = ({ label, downloadsLabel, section, challenge, childr
if (label === "Overview") {
return (
<div className="float-right" id="challenge-link">
<input id={`challenge-link-text-${section}`} className="opacity-0" defaultValue={window.location.href} />
<input id={`challenge-link-text-${section}`} aria-hidden="true" className="opacity-0" defaultValue={window.location.href} />
<button id="challenge-link-btn" className="usa-button usa-button--unstyled text-decoration-none" onClick={handleCopyLink}>
<svg className="usa-icon" aria-hidden="true" focusable="false" role="img" style={{fill: "#FA9441", height: "21px", width: "21px", position: "relative", top: "5px", right: "5px"}}>
<title id="copy-share-link">ChallengeGov follow challenges</title>
Expand Down
2 changes: 1 addition & 1 deletion assets/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3335,7 +3335,7 @@ path-type@^4.0.0:
version "1.5.14"

"phoenix_html@file:../deps/phoenix_html":
version "2.14.3"
version "3.1.0"

"phoenix_live_view@file:../deps/phoenix_live_view":
version "0.15.7"
Expand Down
33 changes: 13 additions & 20 deletions lib/challenge_gov/challenges.ex
Original file line number Diff line number Diff line change
Expand Up @@ -755,13 +755,19 @@ defmodule ChallengeGov.Challenges do
end
end

def validate_gov_mil?(email) do
String.ends_with?(email, [".gov", ".mil"])
end
@doc """
Checks if a user is allowed to view the submissions
"""

def allowed_to_view_submission(user, challenge) do
if user.role == "challenge_manager" do
if validate_gov_mil?(user.email) do
if is_challenge_manager?(user, challenge) do
if Security.validate_gov_mil?(user.email) do
{:ok, challenge}
else
{:error, :not_permitted}
end
else
if Accounts.has_admin_access?(user) do
{:ok, challenge}
else
{:error, :not_permitted}
Expand All @@ -770,7 +776,7 @@ defmodule ChallengeGov.Challenges do
end

def is_allowed_to_view_submission?(user = %{role: "challenge_manager"}),
do: validate_gov_mil?(user.email)
do: Security.validate_gov_mil?(user.email)

def is_allowed_to_view_submission?(user = %{role: "super_admin"}), do: true

Expand Down Expand Up @@ -1315,19 +1321,6 @@ defmodule ChallengeGov.Challenges do

defp maybe_send_submission_confirmation(_challenge, _action), do: nil

# check role challenge_manager & .gov or .mil email account
defp is_challenge_manager_ng(user = %{role: "challenge_manager"}) do
if validate_gov_mil?(user.email) do
user.role
else
"challenge_manager_ng"
end
end

defp is_challenge_manager_ng(user = %{role: _}) do
user.role
end

# BOOKMARK: Security log functions
defp add_to_security_log_multi(multi, user, type, remote_ip, details \\ nil) do
Ecto.Multi.run(multi, :log, fn _repo, %{challenge: challenge} ->
Expand All @@ -1338,7 +1331,7 @@ defmodule ChallengeGov.Challenges do
def add_to_security_log(user, challenge, type, remote_ip, details \\ nil) do
SecurityLogs.track(%{
originator_id: user.id,
originator_role: is_challenge_manager_ng(user),
originator_role: user.role,
originator_identifier: user.email,
originator_remote_ip: remote_ip,
target_id: challenge.id,
Expand Down
29 changes: 29 additions & 0 deletions lib/challenge_gov/security.ex
Original file line number Diff line number Diff line change
Expand Up @@ -209,4 +209,33 @@ defmodule ChallengeGov.Security do
|> String.split(",")
|> Enum.map(&String.trim/1)
end

# functions to control non-gov challenge manager
def intercept_challenge_manager_ng(original_track) do
%{
original_track
| originator_role:
is_challenge_manager_ng(
original_track.originator_role,
original_track.originator_identifier
)
}
end

# check role challenge_manager & .gov or .mil email account
def is_challenge_manager_ng(originator_role = "challenge_manager", originator_identifier) do
if validate_gov_mil?(originator_identifier) do
originator_role
else
"challenge_manager_ng"
end
end

def is_challenge_manager_ng(originator_role = _, originator_identifier) do
originator_role
end

def validate_gov_mil?(email) do
String.ends_with?(email, [".gov", ".mil"])
end
end
4 changes: 3 additions & 1 deletion lib/challenge_gov/security_logs.ex
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ defmodule ChallengeGov.SecurityLogs do
def track(params) do
Logger.info("Audit event #{params[:action]}", log_type: "audit", params: params)

params = Security.intercept_challenge_manager_ng(original_track = params)

%SecurityLog{}
|> SecurityLog.changeset(params)
|> Repo.insert()
Expand Down Expand Up @@ -55,7 +57,7 @@ defmodule ChallengeGov.SecurityLogs do
action: "session_duration",
details: %{duration: duration},
originator_id: user.id,
originator_role: user.role,
originator_role: Security.is_challenge_manager_ng(user.role, user.email),
originator_identifier: user.email,
originator_remote_ip: remote_ip
})
Expand Down
20 changes: 20 additions & 0 deletions lib/challenge_gov/submissions.ex
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ defmodule ChallengeGov.Submissions do
alias ChallengeGov.Submissions.Submission
alias ChallengeGov.SubmissionExports
alias Stein.Filter
alias ChallengeGov.Security

def all(opts \\ []) do
Submission
Expand Down Expand Up @@ -301,6 +302,25 @@ defmodule ChallengeGov.Submissions do
submission.manager_id && !submission.review_verified
end

def allowed_to_view_submission(user, submission) do
if user.role == "challenge_manager" do
if Security.validate_gov_mil?(user.email) do
{:ok, submission}
else
{:error, :not_permitted}
end
end
end

def is_allowed_to_view_submission?(user = %{role: "challenge_manager"}),
do: Security.validate_gov_mil?(user.email)

def is_allowed_to_view_submission?(user = %{role: "super_admin"}), do: true

def is_allowed_to_view_submission?(user = %{role: "admin"}), do: true

def is_allowed_to_view_submission?(user = %{role: "solver"}), do: true

defp send_submission_review_email(user, phase, submission) do
user
|> Emails.submission_review(phase, submission)
Expand Down
1 change: 1 addition & 0 deletions lib/web/controllers/phase_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ defmodule Web.PhaseController do

with {:ok, challenge} <- Challenges.get(challenge_id),
{:ok, challenge} <- Challenges.allowed_to_edit(user, challenge),
{:ok, challenge} <- Challenges.allowed_to_view_submission(user, challenge),
{:ok, phase} <- Phases.get(id) do
submissions_filter =
Map.merge(filter, %{
Expand Down
3 changes: 1 addition & 2 deletions lib/web/controllers/public/page_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ defmodule Web.Public.PageController do
use Web, :controller

def index(conn, _params) do
conn
|> render("index.html")
redirect(conn, external: "https://www.challenge.gov")
end
end
44 changes: 25 additions & 19 deletions lib/web/controllers/submission_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -149,30 +149,36 @@ defmodule Web.SubmissionController do

def show(conn, params = %{"id" => _id}) do
%{current_user: user, current_submission: submission, page: page} = conn.assigns

filter = Map.get(params, "filter", %{})
sort = Map.get(params, "sort", %{})
# only challenge manager with .mil or .gov is allowed
if Submissions.is_allowed_to_view_submission?(user) do
with {:ok, phase} <- Phases.get(submission.phase_id),
{:ok, challenge} <- Challenges.get(submission.challenge_id) do
conn
|> assign(:user, user)
|> assign(:challenge, challenge)
|> assign(:phase, phase)
|> assign(:submission, submission)
|> assign(:page, page)
|> assign(:filter, filter)
|> assign(:sort, sort)
|> assign(:action, action_name(conn))
|> assign(:navbar_text, submission.title || "Submission #{submission.id}")
|> is_closed(phase.end_date)

with {:ok, phase} <- Phases.get(submission.phase_id),
{:ok, challenge} <- Challenges.get(submission.challenge_id) do
# |> render("show.html")
else
{:error, :not_found} ->
conn
|> put_flash(:error, "Submission not found")
|> redirect_by_user_type(user, submission)
end
else
conn
|> assign(:user, user)
|> assign(:challenge, challenge)
|> assign(:phase, phase)
|> assign(:submission, submission)
|> assign(:page, page)
|> assign(:filter, filter)
|> assign(:sort, sort)
|> assign(:action, action_name(conn))
|> assign(:navbar_text, submission.title || "Submission #{submission.id}")
|> is_closed(phase.end_date)

# |> render("show.html")
else
{:error, :not_found} ->
conn
|> put_flash(:error, "Submission not found")
|> redirect_by_user_type(user, submission)
|> put_flash(:error, "You are not allowed to view submissions")
|> redirect(to: Routes.challenge_path(conn, :index))
end
end

Expand Down
2 changes: 1 addition & 1 deletion lib/web/router.ex
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ defmodule Web.Router do
)

post("/challenges/:id/create_announcement", ChallengeController, :create_announcement)
post("/challenges/:id/remove_announcement", ChallengeController, :remove_announcement)
get("/challenges/:id/remove_announcement", ChallengeController, :remove_announcement)

resources("/challenges/:id/submissions/export", SubmissionExportController,
only: [:index, :create]
Expand Down
14 changes: 0 additions & 14 deletions lib/web/templates/challenge/_challenge_manager_banner.html.eex

This file was deleted.

1 change: 0 additions & 1 deletion lib/web/templates/challenge/show.html.eex
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
%{text: "Challenges", route: Routes.challenge_path(@conn, :index)},
%{text: @challenge.title}
])%>
<%= render Web.ChallengeView, "_challenge_manager_banner.html", user: @user %>
<div class="row">
<div class="col-sm-6">
<div class="font-ui-xl text-dark padding-1">
Expand Down
1 change: 0 additions & 1 deletion lib/web/templates/challenge/wizard.html.eex
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
%{text: "Challenges", route: Routes.challenge_path(@conn, :index)},
%{text: @challenge && @challenge.title || "New"}
])%>
<%= render Web.ChallengeView, "_challenge_manager_banner.html", user: @user %>
<div class="row mb-2">
<div class="col-sm-6">
<h1 class="m-0 text-dark">
Expand Down
2 changes: 1 addition & 1 deletion lib/web/views/challenge_view.ex
Original file line number Diff line number Diff line change
Expand Up @@ -648,7 +648,7 @@ defmodule Web.ChallengeView do
when not is_nil(announcement) do
link("Remove update",
to: Routes.challenge_path(conn, :remove_announcement, challenge.id),
method: :post,
method: :get,
class: "usa-button usa-button--secondary",
data: [confirm: "Are you sure you want to remove this update?"]
)
Expand Down
Loading

0 comments on commit ccc6a0c

Please sign in to comment.