Skip to content

Commit

Permalink
Several changes:
Browse files Browse the repository at this point in the history
 - Release notes: moved h3 to inside of <a> tag
 - Added idle timeout
  • Loading branch information
RockinRoel committed Jul 26, 2018
1 parent 9e1cdf2 commit d5e1afa
Show file tree
Hide file tree
Showing 9 changed files with 277 additions and 101 deletions.
2 changes: 1 addition & 1 deletion ReleaseNotes.html
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ <h3>Path parameters</h3>

<p>A feature example demonstrating this was added in <tt>examples/feature/urlparams</tt>.</p>

<h3><a href="classWt_1_1WFileDropWidget.html">WFileDropWidget</a></h3>
<a href="classWt_1_1WFileDropWidget.html"><h3>WFileDropWidget</h3></a>

<p>Added the ability to set a
<a href="classWt_1_1WFileDropWidget.html#a9ad41a8986a7bbb25178e0cda850333d">JavaScript filter</a>, e.g. to
Expand Down
17 changes: 17 additions & 0 deletions src/Wt/WApplication.C
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ WApplication::WApplication(const WEnvironment& env
showLoadingIndicator_("showload", this),
hideLoadingIndicator_("hideload", this),
unloaded_(this, "Wt-unload"),
idleTimeout_(this, "Wt-idleTimeout"),
soundManager_(nullptr)
{
session_->setApplication(this);
Expand Down Expand Up @@ -281,6 +282,7 @@ WApplication::WApplication(const WEnvironment& env
(std::unique_ptr<WLoadingIndicator>(new WDefaultLoadingIndicator()));

unloaded_.connect(this, &WApplication::doUnload);
idleTimeout_.connect(this, &WApplication::doIdleTimeout);
}

void WApplication::setJavaScriptClass(const std::string& javaScriptClass)
Expand Down Expand Up @@ -766,6 +768,21 @@ void WApplication::unload()
quit();
}

void WApplication::doIdleTimeout()
{
const Configuration& conf = environment().server()->configuration();

if (conf.idleTimeout() != -1)
idleTimeout();
}

void WApplication::idleTimeout()
{
const Configuration& conf = environment().server()->configuration();
LOG_INFO("User idle for " << conf.idleTimeout() << " seconds, quitting due to idle timeout");
quit();
}

void WApplication::handleJavaScriptError(const std::string& errorText)
{
LOG_ERROR("JavaScript error: " << errorText);
Expand Down
73 changes: 73 additions & 0 deletions src/Wt/WApplication.h
Original file line number Diff line number Diff line change
Expand Up @@ -2110,6 +2110,77 @@ class WT_API WApplication : public WObject
*/
virtual void unload();

/*! \brief Idle timeout handler
*
* If <tt>idle-timeout</tt> is set in the configuration, this method is called when
* the user seems idle for the number of seconds set in <tt>idle-timeout</tt>.
*
* This feature can be useful in security sensitive applications
* to prevent unauthorized users from taking over the session
* of a user that has moved away from or left behind
* the device from which they are accessing the %Wt application.
*
* The default implementation logs that a timeout has occurred,
* and calls quit().
*
* This method can be overridden to specify different timeout behaviour,
* e.g. to show a dialog that a user's session has expired, or that
* the session is about to expire.
*
* \if cpp
*
* Example for an expiration dialog:
*
* \code
* class MyApplication : public Wt::WApplication {
* public:
* MyApplication(Wt::WEnvironment &env)
* : WApplication(env)
* { }
*
* protected:
* virtual void idleTimeout() override
* {
* if (idleTimeoutDialog_)
* return; // Prevent multiple dialogs
*
* idleTimeoutDialog_ = addChild(std::make_unique<Wt::WDialog>("Idle timeout"));
* idleTimeoutDialog_->contents()->addNew<Wt::WText>("This session will automatically quit in 1 minute, "
* "press 'abort' to continue using the application");
* auto btn = idleTimeoutDialog_->footer()->addNew<Wt::WPushButton>("abort");
* btn->clicked().connect([this]{
* removeChild(idleTimeoutDialog_.get());
* });
* auto timer = idleTimeoutDialog_->addChild(std::make_unique<Wt::WTimer>());
* timer->setInterval(std::chrono::seconds{60});
* timer->setSingleShot(true);
* timer->timeout().connect([this]{
* quit();
* });
* timer->start();
* idleTimeoutDialog_->show();
* }
*
* private:
* Wt::Core::observing_ptr<Wt::WDialog> idleTimeoutDialog_;
* };
* \endcode
*
* \note The events currently counted as user activity are:
* - mousedown
* - mouseup
* - wheel
* - keydown
* - keyup
* - touchstart
* - touchend
* - pointerdown
* - pointerup
*
* \endif
*/
virtual void idleTimeout();

/**
* @brief handleJavaScriptError print javaScript errors to log file.
* You may want to overwrite it to render error page for example.
Expand Down Expand Up @@ -2231,6 +2302,7 @@ class WT_API WApplication : public WObject

EventSignal<> showLoadingIndicator_, hideLoadingIndicator_;
JSignal<> unloaded_;
JSignal<> idleTimeout_;

WContainerWidget *timerRoot() const { return timerRoot_; }
WEnvironment& env(); // short-hand for session_->env()
Expand Down Expand Up @@ -2275,6 +2347,7 @@ class WT_API WApplication : public WObject
void setExposeSignals(bool how) { exposeSignals_ = how; }
bool exposeSignals() const { return exposeSignals_; }
void doUnload();
void doIdleTimeout();

#ifndef WT_TARGET_JAVA
int startWaitingAtLock();
Expand Down
8 changes: 8 additions & 0 deletions src/web/Configuration.C
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ void Configuration::reset()
sessionTracking_ = URL;
reloadIsNewSession_ = true;
sessionTimeout_ = 600;
idleTimeout_ = -1;
bootstrapTimeout_ = 10;
indicatorTimeout_ = 500;
doubleClickTimeout_ = 200;
Expand Down Expand Up @@ -299,6 +300,12 @@ int Configuration::sessionTimeout() const
return sessionTimeout_;
}

int Configuration::idleTimeout() const
{
READ_LOCK;
return idleTimeout_;
}

int Configuration::keepAlive() const
{
int timeout = sessionTimeout();
Expand Down Expand Up @@ -902,6 +909,7 @@ void Configuration::readApplicationSettings(xml_node<> *app)
}

setInt(sess, "timeout", sessionTimeout_);
setInt(sess, "idle-timeout", idleTimeout_);
setInt(sess, "bootstrap-timeout", bootstrapTimeout_);
setInt(sess, "server-push-timeout", serverPushTimeout_);
setBoolean(sess, "reload-is-new-session", reloadIsNewSession_);
Expand Down
2 changes: 2 additions & 0 deletions src/web/Configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ class WT_API Configuration
SessionTracking sessionTracking() const;
bool reloadIsNewSession() const;
int sessionTimeout() const;
int idleTimeout() const;
int keepAlive() const; // sessionTimeout() / 2, or if sessionTimeout == -1, 1000000
int multiSessionCookieTimeout() const; // sessionTimeout() * 2
int bootstrapTimeout() const;
Expand Down Expand Up @@ -278,6 +279,7 @@ class WT_API Configuration
SessionTracking sessionTracking_;
bool reloadIsNewSession_;
int sessionTimeout_;
int idleTimeout_;
int bootstrapTimeout_;
int indicatorTimeout_;
int doubleClickTimeout_;
Expand Down
3 changes: 3 additions & 0 deletions src/web/WebRenderer.C
Original file line number Diff line number Diff line change
Expand Up @@ -1024,6 +1024,9 @@ void WebRenderer::serveMainscript(WebResponse& response)

script.setVar("KEEP_ALIVE", std::to_string(conf.keepAlive()));

script.setVar("IDLE_TIMEOUT", conf.idleTimeout() != -1 ?
std::to_string(conf.idleTimeout()) : std::string("null"));

script.setVar("INDICATOR_TIMEOUT", conf.indicatorTimeout());
script.setVar("SERVER_PUSH_TIMEOUT", conf.serverPushTimeout() * 1000);

Expand Down
57 changes: 57 additions & 0 deletions src/web/skeleton/Wt.js
Original file line number Diff line number Diff line change
Expand Up @@ -2951,6 +2951,8 @@ var sessionUrl,
responsePending = null,
pollTimer = null,
keepAliveTimer = null,
idleTimeout = _$_IDLE_TIMEOUT_$_, /* idle timeout in seconds, null if disabled */
idleTimeoutTimer = null,
commErrors = 0,
serverPush = false,
updateTimeout = null;
Expand All @@ -2962,6 +2964,10 @@ function quit(hasQuitMessage) {
clearInterval(keepAliveTimer);
keepAliveTimer = null;
}
if (idleTimeoutTimer) {
clearTimeout(idleTimeoutTimer);
idleTimeoutTimer = null;
}
if (pollTimer) {
clearTimeout(pollTimer);
pollTimer = null;
Expand All @@ -2987,6 +2993,56 @@ function setTitle(title) {
document.title = title;
}

function doIdleTimeout() {
self.emit(self, 'Wt-idleTimeout');
idleTimeoutTimer = setTimeout(doIdleTimeout, idleTimeout * 1000);
}

function delayIdleTimeout() {
if (idleTimeoutTimer !== null) {
clearTimeout(idleTimeoutTimer);
idleTimeoutTimer = setTimeout(doIdleTimeout, idleTimeout * 1000);
}
}

function initIdleTimeout() {
var opts = true;

if (idleTimeout === null)
return;

idleTimeoutTimer = setTimeout(doIdleTimeout, idleTimeout * 1000);

try {
var options = Object.defineProperty({}, "passive", {
get: function() {
//passive supported
opts = {
capture: true,
passive: true
};
}
});

window.addEventListener('test', options, options);
window.removeEventListener('test', options, options);
} catch (err) {
opts = true; // passive not supported, only specify capture
}

if (document.addEventListener) {
document.addEventListener('mousedown', delayIdleTimeout, opts);
document.addEventListener('mouseup', delayIdleTimeout, opts);
document.addEventListener('wheel', delayIdleTimeout, opts);
document.addEventListener('keydown', delayIdleTimeout, opts);
document.addEventListener('keyup', delayIdleTimeout, opts);
document.addEventListener('touchstart', delayIdleTimeout, opts);
document.addEventListener('touchend', delayIdleTimeout, opts);
document.addEventListener('pointerdown', delayIdleTimeout, opts);
document.addEventListener('pointerup', delayIdleTimeout, opts);
}
}

function load(fullapp) {
if (loaded)
return;
Expand Down Expand Up @@ -3018,6 +3074,7 @@ function load(fullapp) {

WT.history._initialize();
initDragDrop();
initIdleTimeout();
loaded = true;

if (fullapp)
Expand Down
Loading

0 comments on commit d5e1afa

Please sign in to comment.