-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[34] Timeout Warning #115
Merged
Merged
[34] Timeout Warning #115
Changes from 15 commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
6aa995a
34 Add session timeout
cpreisinger d31cd9e
34 Added session timeout warning modal
cpreisinger 745a193
34 Fix failing session request spec
cpreisinger f806d14
34 Timeout redirect, user activity, and countdown
cpreisinger cdff3a0
Merge branch 'dev' of github.com:GSA/Challenge_platform into 34/timeo…
cpreisinger c198e1e
34 Revert tool-versions file
cpreisinger cebbd9e
Merge branch 'dev' into 34/timeout-warning
stepchud 30c8b57
34 Fix session expiration condition and countdown
cpreisinger 16be079
Merge branch '34/timeout-warning' of github.com:GSA/Challenge_platfor…
cpreisinger f7ba233
34 Fix failing session timeout test
cpreisinger a18c619
34 Change session timeout env var to a constant
cpreisinger d50cefc
34 Remove session timeout from .envrc
cpreisinger 946afaa
34 Fix for timeout not redirecting properly
cpreisinger d6ff17e
Merge branch '34/timeout-warning' of github.com:GSA/Challenge_platfor…
cpreisinger b135906
34 Readability fix for check_session_expiration
cpreisinger 96e444a
34 Use skip before action instead of except for timeout
cpreisinger b7f1c15
Merge branch 'dev' into 34/timeout-warning
cpreisinger File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
ruby 3.2.4 | ||
ruby 3.2.4 | ||
nodejs 20.15.1 | ||
yarn 1.22.22 | ||
yarn 1.22.22 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
import { formatMilliseconds } from "./time_helpers"; | ||
|
||
document.addEventListener("DOMContentLoaded", function () { | ||
var sessionStartTime = Date.now(); | ||
|
||
const sessionTimeoutMinutes = window.appConfig.sessionTimeoutMinutes; | ||
const warningTimeoutMinutes = 2; | ||
const sessionTimeoutMs = sessionTimeoutMinutes * 60 * 1000; | ||
const warningTimeoutMs = | ||
(sessionTimeoutMinutes - warningTimeoutMinutes) * 60 * 1000; | ||
// Debug overrides | ||
// const sessionTimeoutMs = 10000; | ||
// const warningTimeoutMs = 5000; | ||
|
||
const renewalModal = document.getElementById("renew-modal"); | ||
const renewalModalOpenButton = document.getElementById( | ||
"renew-modal-open-button" | ||
); | ||
const renewalModalCloseButton = document.getElementById( | ||
"renew-modal-close-button" | ||
); | ||
const countdownDiv = document.querySelector("#renew-modal .countdown"); | ||
countdownDiv.textContent = formatMilliseconds(warningTimeoutMs); | ||
|
||
const activityRenewalInterval = 1000; | ||
var doRenewSession = false; | ||
var ignoreNextActivity = false; | ||
|
||
const showTimeoutWarning = () => { | ||
ignoreNextActivity = true; | ||
renewalModalOpenButton.click(); | ||
ignoreNextActivity = false; | ||
}; | ||
|
||
const updateCountdown = () => { | ||
var timeRemaining = sessionTimeoutMs - (Date.now() - sessionStartTime); | ||
countdownDiv.textContent = formatMilliseconds(timeRemaining); | ||
}; | ||
|
||
const logoutSession = () => { | ||
fetch("/sessions/timeout", { | ||
method: "DELETE", | ||
headers: { | ||
"X-CSRF-Token": document.querySelector('meta[name="csrf-token"]') | ||
.content, | ||
"Content-Type": "application/json", | ||
}, | ||
}).then((response) => { | ||
if (response.ok) { | ||
window.location.href = "/"; | ||
} | ||
}); | ||
}; | ||
|
||
const handleUserActivity = (event) => { | ||
// Don't count the modal showing and hiding as user activity | ||
if (ignoreNextActivity) { | ||
return; | ||
} | ||
|
||
ignoreNextActivity = true; | ||
renewalModalCloseButton.click(); | ||
ignoreNextActivity = false; | ||
|
||
doRenewSession = true; | ||
}; | ||
|
||
document.addEventListener("click", handleUserActivity); | ||
document.addEventListener("keydown", handleUserActivity); | ||
document.addEventListener("scroll", handleUserActivity); | ||
|
||
setInterval(() => { | ||
if (doRenewSession) { | ||
renewSession(); | ||
} | ||
}, activityRenewalInterval); | ||
|
||
document | ||
.getElementById("extend-session-button") | ||
.addEventListener("click", () => { | ||
renewSession(); | ||
}); | ||
|
||
var renewSession = () => { | ||
fetch("/sessions/renew", { | ||
method: "POST", | ||
headers: { | ||
"X-CSRF-Token": document | ||
.querySelector('meta[name="csrf-token"]') | ||
.getAttribute("content"), | ||
}, | ||
}).then((response) => { | ||
if (response.ok) { | ||
clearTimeout(timeoutWarning); | ||
clearTimeout(sessionTimeout); | ||
|
||
sessionStartTime = Date.now(); | ||
|
||
timeoutWarning = setTimeout(() => { | ||
showTimeoutWarning(); | ||
}, warningTimeoutMs); | ||
|
||
sessionTimeout = setTimeout(() => { | ||
logoutSession(); | ||
}, sessionTimeoutMs); | ||
|
||
doRenewSession = false; | ||
} | ||
}); | ||
}; | ||
|
||
var timeoutWarning = setTimeout(() => { | ||
showTimeoutWarning(); | ||
}, warningTimeoutMs); | ||
|
||
var sessionTimeout = setTimeout(() => { | ||
logoutSession(); | ||
}, sessionTimeoutMs); | ||
|
||
var countdownInterval; | ||
|
||
var startCountdown = () => { | ||
clearInterval(countdownInterval); | ||
countdownInterval = setInterval(updateCountdown, 1000); | ||
}; | ||
|
||
startCountdown(); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
export function formatMilliseconds(ms) { | ||
const totalSeconds = Math.round(ms / 1000); | ||
const minutes = Math.floor(totalSeconds / 60); | ||
const seconds = totalSeconds % 60; | ||
return `${minutes}:${seconds < 10 ? "0" : ""}${seconds}`; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
<a href="#renew-modal" style="display:none;" id="renew-modal-open-button" class="usa-button" aria-controls="renew-modal" data-open-modal></a> | ||
|
||
<div | ||
stepchud marked this conversation as resolved.
Show resolved
Hide resolved
|
||
class="usa-modal" | ||
id="renew-modal" | ||
aria-labelledby="modal-1-heading" | ||
aria-describedby="modal-1-description" | ||
> | ||
<div class="usa-modal__content"> | ||
<div class="usa-modal__main"> | ||
<h2 class="usa-modal__heading" id="modal-1-heading"> | ||
Session expire | ||
</h2> | ||
<div class="usa-prose"> | ||
<p id="modal-1-description"> | ||
Your session will expire in <span class="countdown"></span><br> | ||
Please click below if you would like to continue. | ||
</p> | ||
</div> | ||
<div class="usa-modal__footer"> | ||
<button class="usa-button modal-btn" id="extend-session-button" data-close-modal type="button">Renew Session</button> | ||
</div> | ||
</div> | ||
<a href="#renew-modal" style="display:none;" id="renew-modal-close-button" class="usa-button" data-close-modal></a> | ||
</div> | ||
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<% flash.each do |key, value| %> | ||
<% alert_class = case key.to_sym | ||
when :notice then "usa-alert--success" | ||
when :alert then "usa-alert--error" | ||
when :error then "usa-alert--error" | ||
else "usa-alert--info" | ||
end %> | ||
|
||
<div class="usa-alert <%= alert_class %> usa-alert--slim"> | ||
<div class="usa-alert__body"> | ||
<p class="usa-alert__text"><%= value %></p> | ||
</div> | ||
</div> | ||
<% end %> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -40,4 +40,31 @@ | |
expect(response).to have_http_status(:redirect) | ||
expect(response).to redirect_to("/dashboard") | ||
end | ||
|
||
it "times out the session" do | ||
session_timeout_in_minutes = SessionsController::SESSION_TIMEOUT_IN_MINUTES | ||
|
||
email = "[email protected]" | ||
token = SecureRandom.uuid | ||
|
||
User.create!({ email:, token: }) | ||
|
||
code = "ABC123" | ||
login_gov = instance_double(LoginGov) | ||
allow(LoginGov).to receive(:new).and_return(login_gov) | ||
allow(login_gov).to receive(:exchange_token_from_auth_result).with(code).and_return( | ||
[{ email:, sub: token }] | ||
) | ||
get "/auth/result", params: { code: } | ||
|
||
expect(session[:userinfo]).not_to be_nil | ||
expect(session[:session_timeout_at]).not_to be_nil | ||
|
||
travel_to (session_timeout_in_minutes.to_i + 1).minutes.from_now do | ||
get dashboard_path | ||
|
||
expect(session[:userinfo]).to be_nil | ||
expect(session[:session_timeout_at]).to be_nil | ||
end | ||
end | ||
end |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
whitespace