Global timer in JavaScript - javascript

A new page is created on my website, website.com/NewPage
I want the video on this page to start in 20 seconds of the page being created.
At the moment, I have a setTimeout function that waits 20 seconds then starts the video. The problem with that is the 20 second timer starts when EACH USER connects. My goal is to have the website start the video 20 seconds after the page is created, for everyone. Here is an example:
User A enters website.com/NewPage within 3 seconds of the page being created.
User B enters website.com/NewPage within 15 seconds of the page being created.
5 seconds after User B connects, User A's video starts.
User B is at 5 seconds and has to wait 15 seconds for the video to start.
My goal is to get it so that the video starts for everyone at the exact same time, as long as they joined before 20 seconds (Nobody else can join after 20 seconds).
So even if User B joined late, It will start at the exact same time for everyone.

It has to be coordinated on the server. You tagged this with long-polling, so I suppose that's the server communications technique you are using. When the first long-polling connection is opened for a new page, then start a timer on the server.

Since you are sharing a timer among different users, I think you need to maintain the timer in the backend. And in the front-end JavaScript, maintain a separate timer for each user (on their local browser).
Say, your front-end code maybe:
var timer = null;
document.onload = function() {
$.ajax({
url: '/server/timer',
type: 'get',
data: {userName: 'user A'}
}).done(function (res) {
if (res.remaining && res.remaining >= 0) {
alert('Hi, please wait for ' + res.remaining + ' seconds to start playing video');
timer = setTimeout(function() {
// play the video
}, res.remaining * 1000);
} else {
alert('Sorry, you cannot watch the video now');
}
});
}
In your backend code, maintain the API /server/timer to make sure the countdown is the same for every user.

Related

Log a user out of a website when they put their computer to sleep

This is a bizarre one. We have a Laravel website, and on said site we have a timer per user, where they get 15 minutes of being inactive before being booted.
We do this through a timer that sits on the page in a react component, it works as we want it to, but now we have a new issue: If a user is logged in and shut the lid of their laptop the website should boot them. Banks do this, Schools and Universities do this, Government sites also do this. So it is possible, just not sure how.
We do use web sockets, using laravel-websockets library and Echo. What I would like to see happen is:
Once you close your laptop boot you to the login screen. So the next time you open the laptop and login, and see the browser you are on the login screen. It doesn't have to happen that quickly, but we need a way to send something to the front end basically telling them to refresh the page, once the session is killed, we set the session lifetime on laravel of 15 minutes.
Some people have suggested in other similar questions:
to create a custom web-socket handler
To compare the session cookie (in the browser) with the user cookie on the back end.
To have a timer running on the front end (we do, it just stops when you close the laptop lid)
The most popular one seems to be using web-sockets, listening for the user to disconnect and then boot them, which is fine and all, but then how do you send a request to a browser thats suspended to then boot them?
I have found requestIdleCallback() But again, I don't think this is what I want if I already have a heartbeat timer on the site. It also doesn't work in all browsers.
I am very lost here on how to accomplish this, the example I can give is:
Log in to your bank, put your computer to sleep, wait 15-20 minutes, awaken the computer, log in and see your bank now has you on the login screen. That's what I want. But I don't know how to accomplish that.
You cant send events to a "sleeping" browser from the back end, and while yes this would have to be a back end solution, how do you update the front end then, so that they are on the logout screen when they reawaken the laptop or computer?
First, let's expand on why Banking websites log you out after 15 minutes without activity. It's a PCI requirement for security.
PCI-DSS requirement 8.1.8:
8.1.8 If a session has been idle for more than 15 minutes, require the user to re-authenticate to re-activate the terminal or session.
In order to achieve this the solution is actually far more primitive than you imagine it to be. It neither requires the use of websockets nor knowing anything about the state of the client's machine (sleep or awake or otherwise). All that is required is knowing the time between the current request using that session and last request using the same session and ensuring they are not greater than 15 minutes apart. If they are the user is to be re-authenticated. If they aren't you may proceed with the request.
The "session timed out" message
You're probably then wondering (if it's that simple) how does the session timed out message appear when you put the computer to sleep and wake it back up. This part is deceptively simple.
When the computer is put to sleep the browser actually disconnects all TCP/IP connections which in turn shuts down the event loop in the javascript engine. So timers don't work. But when the browser wakes up again it attempts to refresh some things including the page itself. So when the page is refreshed the request goes back out to the server invoking the server to require the user re-authenticate.
However, this won't account for the javascript message modal (if that's what you're referring to) which some banking websites do. Also not all browsers do a hard refresh on the page in all scenarios. So another approach can be taken. Rather than have a timer in the browser that times out after 15 minutes you can simply store the page load time in javascript as a timestamp and have a 1 second interval time out that compares that timestamp to the computer's current timestamp. If they are more than 15 minutes apart, the session should be terminated.
window.onload = function() {
sessionStart = Date.now();
timer = setInterval(function() {
if (Date.now() - sessionStart > 15 * 60 * 1000) {
clearTimeout(timer);
alert("Session Timed out!");
window.location = "http://www.example.com/login";
}
}, 1000);
};
Even if the computer goes to sleep and the timer stops, the session will eventually time out on the server side (see section below for details) and when the computer wakes up again the timer with a 1 second interval will eventually startup again, invoking the message (as if the user timed out while the computer was asleep). The time lost between the time the computer went to sleep and the time the computer wakes up won't matter as the timestamp will remain in memory. The disconnect between the client and server is unimportant because they don't need to communicate this information in order for the session to be properly terminated on the server side. The server can do its own garbage collection and terminate the session without communication from the client (i.e asynchronously).
Believe it or not Banks don't care about activity inside of the client. They only care about request activity to the server. So if you're wondering how do they keep the session alive for greater than 15 minutes when the user is on the same page for that long, they simply send a AJAX request in the background to refresh the session after asking the user if they still want to continue.
This can be done in the same onload event callback we used earlier like so:
window.onload = function() {
sessionStart = Date.now();
timer = setInterval(function() {
if (Date.now() - sessionStart > 10 * 60 * 1000) {
if (confirm("Your session is about to timeout. Do you wish to continue?")) {
// send ajax request to refresh session TTL here
// reset the timer
sessionStart = Date.now();
}
} else if (Date.now() - sessionStart > 15 * 60 * 1000) {
clearTimeout(timer);
alert("Session Timed out!");
window.location = "http://www.example.com/login";
}
}, 1000);
};
Handling session termination on the server side
To handle the session termination on the server side there are several approaches. Depending on which one you use you will need different tactics. One is using PHP's default session handler and setting the session.max_lifetime to expire after 15 minutes (this deletes the session data entirely on the server side thus invalidating the client's cookie).
If you let the default session handler mechanism do it you can run into issues depending on which handler is used (files, memcached, redis, custom, etc).
With the files (default handler) the garbage collection happens in one of two ways:
Most Debian based systems do their own GC through a cron job (which works out great for your scenario)
Other distros let PHP's default GC mechanism handle it, which is based on a probabilistic outcome from each incoming request to PHP that checks file mtime's on session files and deletes those past their session.max_lifetime. The problem with this approach is that on low-traffic sites a session could potentially sit there on the server for a long time until enough requests come in (depending on the session.gc_probability score) to invoke the GC to clean up the session files.
With memcached and redis based handlers you don't have this problem. They will handle purging the memory automatically. Sessions may still remain in physical memory for a time past their lifetime, but the daemon will not be able to access them. If you're concerned about this bit for security you can encrypt your sessions at rest or find a key/value store that has stricter memory purging GC mechanism.
With a custom session handler you will have to build your own GC mechanism. Through SessionHandlerInterface you'd implement a gc method that hand you the session's maximum lifetime interval and you'd be responsible for verifying if the session has passed its lifetime based on this interval and do your garbage collection from there.
You can also setup a separate end-point that checks the session TTL (via asynchronous AJAX request on the client side) and sends back a response if the session has expired (forcing the javascript to re-authenticate the user).
UPDATE
Regarding the WebSocket request, I assume you're using Laravel WebSockets with pusher. Pusher.io does not support timeout, you can read this support article "Do you plan to add a connection timeout feature to the Channels pusher-js client library?". You can test it out if you enable Laravel debug mode (APP_DEBUG=true inside .env) and beggin laravel-websockets from terminal (php artisan websockets:serve) so you can see the output log events. If you try to close the laptop lid or set computer to hibernation mode (sleep), you won't see any messages regarding this event. You cannot do it with the pusher protocol. There is the member_removed Presence event, but that triggers only when you close the tab or you logout. Of course you can trigger your client custom event to the presence channel, but to do that you also need a timer setup to the client side and you'll have to create a service provider for the laravel-websockets server like this github issue "Exist a way to implement webhooks?".
Some people have suggested in other similar questions:
...
To have a timer running on the front end (we do, it just stops when you close the laptop lid)
That happens because client timers halt execution on hibernation, thus they continue from where they were before. But if you use a date variable to save the time, that variable will not get updated when the computer goes to hibernation, thus you'll know when it goes out from sleep by checking that date variable which in compare to current time will have significant difference and will be greater than the timer interval.
Implementing time logic in client
You can also see this implementation to this related Q/A: Can any desktop browsers detect when the computer resumes from sleep?
You can setup a timer in the client to run each minute. We won't rely on the timer interval, but instead that timer will check an outer scope date variable if the time span since last timer is greater than 15 minutes; if it is, then that means that the browser/JS halted execution for some reason, possibly hibernation of the device (sleep) and then you redirect the user to the logout route.
Example JS client code:
// Set a variable to check previous time
let clientSession = new Date;
// Setup the client session checking timer
let clientSessionTimer = setInterval(() => {
const now = new Date;
// Get how many seconds have passed since last check
const secondsSpan = (now - clientSession) / 1000;
// If the 1 minute timer has exceeded 15 minutes trigger logout and clear timer
if (secondsSpan > (60 * 15)) {
// For some reason JS halted execution, so we'll proceed with logging out
clearInterval(clientSessionTimer);
window.location.href = '/logout/session'
} else {
// The timer runs as it should, update the clientSession time
clientSession = now;
}
}, 1000 * 60);
You can check this simple example but using 1 second timer with 15 seconds logout here. Best to test it on a laptop with closing the lid and then open it again after 15 seconds a minute of two, because if you have many programs running, the computer takes some time to save memory state so to complete hibernation mode and halt execution.
Web Workers Example
You can even use Web Workers API to setup a web worker to be much safer:
Page JS code:
const logoutWorker = new Worker('logoutWorker.js');
logoutWorker.onmessage = function (ev) {
if (ev && ev.data === 'wakeup') {
logoutWorker.terminate();
// window.location.href = '/logout/session'
} else {
// The timer runs as it should, nothing to do
}
}
Web worker logoutWorker.js code:
let clientSession = new Date();
let clientSessionTimer = setInterval(() => {
const now = new Date;
const secondsSpan = (now - clientSession) / 1000;
if (secondsSpan > 15) {
postMessage('wakeup'); // Send a message wakeup to the worker page
clearInterval(clientSessionTimer); // Clear the timer
} else {
clientSession = now; // Update the clientSession timer variable
postMessage('update'); // And post a message to the page ONLY IF needed
}
}, 1000);
You can also check the Web Worker example with the same 15 seconds timer here.
So Idea is behind setInterval and Sockets,
setInterval is supported in most browsers and javascript WbsocketApi is supported in almost everybrowser.
Brief overview:
setInterval() - this function behaviour is following when your computer is at sleep/suspended/hibernate mode it is paused and when you are at awaken mode it resumes itself.
The following code does the following, at first(maybe at the same time but) it starts php server_socket listening to the connections,
than javascript websocket api sends current timestamp in Unix timestamp milliseconds in every 2 seconds you can have 1 second it is up to you.
after that php server socket is getting this time and checks if it has anything like previous time to compare, when the code is first instantiated php does not has anything like previous time to compare it to the time which was sent from javascript websocket, so php does nothing but saves this time in the session called 'prev_time' and waits for another time data to be recieved from javascript socket, so here begins second cycle.
when php server socket new time data from javascript WebsocketApi it checks it has anything like previous time to compare to this newly received time data, it means that php checks if session called 'prev_time' exists, as we are in the second cycle php discovers that it exists, grabs it's value and does following $diff = $new_time - $prev_time, $diff will be 2 seconds or 2000 miliseconds because remember our setInterval cycle happens in every 2 seconds and time format we are sending is in miliseconds,
than php checks if($diff<3000) if difference is less than 3000 if it is it knows that user is active, again you can manipulate this seconds as you wish, I choose 3000 because possible latency in the network which is almost impossible but you know I am always cautious when it comes to networks, so let's continue, when php determines that user is active php just resets 'prev_time' session with the value of $new_time which was newly received and just for testing purposes it sends message back to javascript socket,
but if $diff is more than 3000 it means that something paused our setInterval and there is only way it can happen and I think you already know what I am saying, so in the else logic of ( if($diff<3000) ) you can logout user by destroying specific session and if you want to redirect you can send some text to javacript socket and create a logic which will execute window.location = "/login" depending on the text, that's it here is the code:
First it is index.html file just to load javascript:
<html>
<body>
<div id="printer"></div>
<script src="javascript_client_socket.js"></script>
</body>
</html>
then it is javascript it is not really beautifully coded but you can figure out READ COMMENTS THEY ARE IMPORTANT:
var socket = new WebSocket('ws://localhost:34237'); // connecting to socket
// Open the socket
socket.onopen = function(event) { // detecting when connection is established
setInterval(function(){ //seting interval for 2 seconds
var date = new Date(); //grabing current date
var nowtime = Date.parse(date); // parisng it in miliseconds
var msg = 'I am the client.'; //jsut testing message
// Send an initial message
socket.send(nowtime); //sending the time to php socket
},2000);
};
// Listen for messages
socket.onmessage = function(event) { //print text which will be sent by php socket
console.log('php: ' + event.data);
};
// Listen for socket closes
socket.onclose = function(event) {
console.log('Client notified socket has closed', event);
};
now here is part of php code, don't worry down there is full code too but this part is actually what does above mentioned jobs you will meet other functions too but they are for decoding and working with javascript sockets so it is actual thing right here READ COMMENTS THEY ARE IMPORTANT:
<?php
$decoded_data = unmask($data /* $data is actual data received from javascript socket */); //grabbing data and unmasking it | unmasking is for javascript sockets don't mind this
print("< ".$decoded_data."\n");
$response = strrev($decoded_data);
$jsTime = (int) $decoded_data; /* time sent by javascript in MILISECONDS IN UNIX FORMAT */
if (isset($_SESSION['prev_time'])) { /** check if we have stored previous time in the session */
$prev_time = (int) $_SESSION['prev_time']; /** grabbing the previous time from session */
$diff = $jsTime-$prev_time; /** getting the difference newly sent time and previous time by subtracting */
print("$jsTime - $prev_time = $diff"); /** printing the difference */
if($diff<3000){ /** checking if difference is less than 3 second if it is it means pc was not at sleep
*** you can manipulate and have for example 1 second = 1000ms */
socket_write($client,encode("You are active! your pc is awakend"));
$_SESSION['prev_time'] = $jsTime; /** saving newly sent time as previous time for future testing whcih will happen in two seconds in our case*/
}else { /** if it is more than 3 seconds it means that javascript setInterval function was paused and resumed after 3 seconds
** So it means that it was at sleep because when your PC is at sleep/suspended/hibernate mode setINterval gets pauesd */
socket_write($client,encode("You are not active! your pc is at sleep"));
$_SESSION['prev_time'] = $jsTime;
}
}else { /** if we have not saved the previous time in session save it */
$_SESSION['prev_time'] = $jsTime;
}
print_r($_SESSION);
?>
And here is the full code of php:
<?php
//Code by: Nabi KAZ <www.nabi.ir>
session_abort();
// set some variables
$host = "127.0.0.1";
$port = 34237;
date_default_timezone_set("UTC");
// don't timeout!
set_time_limit(0);
// create socket
$socket = socket_create(AF_INET, SOCK_STREAM, 0)or die("Could not create socket\n");
// bind socket to port
$result = socket_bind($socket, $host, $port)or die("Could not bind to socket\n");
// start listening for connections
$result = socket_listen($socket, 20)or die("Could not set up socket listener\n");
$flag_handshake = false;
$client = null;
do {
if (!$client) {
// accept incoming connections
// client another socket to handle communication
$client = socket_accept($socket)or die("Could not accept incoming connection\n");
}
$bytes = #socket_recv($client, $data, 2048, 0);
if ($flag_handshake == false) {
if ((int)$bytes == 0)
continue;
//print("Handshaking headers from client: ".$data."\n");
if (handshake($client, $data, $socket)) {
$flag_handshake = true;
}
}
elseif($flag_handshake == true) {
/*
**** Main section for detectin sleep or not **
*/
if ($data != "") {
$decoded_data = unmask($data /* $data is actual data received from javascript socket */); //grabbing data and unmasking it | unmasking is for javascript sockets don't mind this
print("< ".$decoded_data."\n");
$response = strrev($decoded_data);
$jsTime = (int) $decoded_data; /* time sent by javascript in MILISECONDS IN UNIX FORMAT */
if (isset($_SESSION['prev_time'])) { /** check if we have stored previous time in the session */
$prev_time = (int) $_SESSION['prev_time']; /** grabbing the previous time from session */
$diff = $jsTime-$prev_time; /** getting the difference newly sent time and previous time by subtracting */
print("$jsTime - $prev_time = $diff"); /** printing the difference */
if($diff<3000){ /** checking if difference is less than 3 second if it is it means pc was not at sleep
*** you can manipulate and have for example 1 second = 1000ms */
socket_write($client,encode("You are active! your pc is awakend"));
$_SESSION['prev_time'] = $jsTime; /** saving newly sent time as previous time for future testing whcih will happen in two seconds in our case*/
}else { /** if it is more than 3 seconds it means that javascript setInterval function was paused and resumed after 3 seconds
** So it means that it was at sleep because when your PC is at sleep/suspended/hibernate mode setINterval gets pauesd */
socket_write($client,encode("You are not active! your pc is at sleep"));
$_SESSION['prev_time'] = $jsTime;
}
}else { /** if we have not saved the previous time in session save it */
$_SESSION['prev_time'] = $jsTime;
}
print_r($_SESSION);
/*
**** end of Main section for detectin sleep or not **
*/
}
}
} while (true);
// close sockets
socket_close($client);
socket_close($socket);
$client = null;
$flag_handshake = false;
function handshake($client, $headers, $socket) {
if (preg_match("/Sec-WebSocket-Version: (.*)\r\n/", $headers, $match))
$version = $match[1];
else {
print("The client doesn't support WebSocket");
return false;
}
if ($version == 13) {
// Extract header variables
if (preg_match("/GET (.*) HTTP/", $headers, $match))
$root = $match[1];
if (preg_match("/Host: (.*)\r\n/", $headers, $match))
$host = $match[1];
if (preg_match("/Origin: (.*)\r\n/", $headers, $match))
$origin = $match[1];
if (preg_match("/Sec-WebSocket-Key: (.*)\r\n/", $headers, $match))
$key = $match[1];
$acceptKey = $key.'258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
$acceptKey = base64_encode(sha1($acceptKey, true));
$upgrade = "HTTP/1.1 101 Switching Protocols\r\n".
"Upgrade: websocket\r\n".
"Connection: Upgrade\r\n".
"Sec-WebSocket-Accept: $acceptKey".
"\r\n\r\n";
socket_write($client, $upgrade);
return true;
} else {
print("WebSocket version 13 required (the client supports version {$version})");
return false;
}
}
function unmask($payload) {
$length = ord($payload[1]) & 127;
if ($length == 126) {
$masks = substr($payload, 4, 4);
$data = substr($payload, 8);
}
elseif($length == 127) {
$masks = substr($payload, 10, 4);
$data = substr($payload, 14);
}
else {
$masks = substr($payload, 2, 4);
$data = substr($payload, 6);
}
$text = '';
for ($i = 0; $i < strlen($data); ++$i) {
$text .= $data[$i] ^ $masks[$i % 4];
}
return $text;
}
function encode($text) {
// 0x1 text frame (FIN + opcode)
$b1 = 0x80 | (0x1 & 0x0f);
$length = strlen($text);
if ($length <= 125)
$header = pack('CC', $b1, $length);
elseif($length > 125 && $length < 65536)$header = pack('CCS', $b1, 126, $length);
elseif($length >= 65536)
$header = pack('CCN', $b1, 127, $length);
return $header.$text;
}
NOTE READ IT:
$new_time variable is $jsTime in Code
create folder and just copy and paste this in files run php socket with the command: php -f server_socket.php go to the localhost and test it open console to see messages it will say "you are active" or "you are not active"(when you come from sleep); your executin will happen when user will come from sleep not when they are at sleep cause at that moment everything is cached in pagefile(windows) or in swap(linux)
I think i have a idea, you've discussed a lot about how bank login/logout system works.
Case-1: Access of webpage to user for unlimited time if user is active
Whenever user logged in, Start a timer on your backend(set the time limit whatever you want), let's say 15 mins. Now what it means?? It means if user doesn't perform any activity on the webpage, then we'll log him/her out.
Now, from front you can send the user activity to your backend(could be send using socket or long polling), which will basically reset the timer and user can use the webpage actively for whatever time they want.
If user put their PC on sleep, timer won't reset and you can invalidate the session once timer ends.
If you want to invalidate the user session as soon as they put their pc on sleep, you may set the limit of the session validate time. For example, when user logs-in, we'll create the session which will be valid only for 10 secs, and once we receive the user activity request, we can reset the timer and provide a new session key.
I hope this helps you. Let me know if you've any question.
If you update a timestamp in the user record with each heartbeat received from the client (e.g. a column called "lastHeartbeat"), you could use your database's Scheduled Event functionality to log them off without any need for the browser to be active on the client side. See Working with MySQL Scheduled Events
DELIMITER $$
DROP EVENT IF EXIST autoLogOff_event;
CREATE EVENT autoLogOff_event
ON SCHEDULE EVERY 1 MINUTE
STARTS CURRENT_TIMESTAMP
ENDS CURRENT_TIMESTAMP + INTERVAL 24 HOUR
DO
BEGIN
UPDATE users SET logOffTime = NOW()
WHERE lastHeartbeat < NOW( ) - INTERVAL 20 MINUTE
END
END $$
DELIMITER ;
I wrote a script to detect if the machine went to sleep. Idea is that when the machine is in sleep mood all all scripts will stop. Therefore if we keep track of the current time within a timeInterval. Everytime the timeInterval triggers the current time minus(-) the new time should be close enough to the timeInterval. Therefor if we want to check if timer was idle for X time, we can check if the time difference is more than X.
Example blow checks if the computer was put to sleep for more than 15s. Please note when you put the computer to sleep it make take about another extra 15s to idea all processors. (When tested on MY PC).
(function() {
this.SleepTimer = function() {
// console.log('sleep timer initiated');
// Create global element references
this.sleepTimer = null;
this.maxTime = null;
this.curDate = null;
this.newDate = null;
this.timer = null;
this.timeInterval = 1000;
this.sleepTimer = new CustomEvent("sleepTimer", {
"detail": {
"maxTime":this.maxTime,
"idelFor": this.newDate - this.curDate,
"timer": this.timer
}
});
// Define option defaults
var defaults = {
maxTime: 10000,
timeInterval: 1000,
autoStart: true,
console: false,
onStart: null,
onIdel: null
}
// Create options by extending defaults with the passed in arugments
if (arguments[0] && typeof arguments[0] === "object") {
this.options = extendDefaults(defaults, arguments[0]);
}
if (this.options.timeInterval) {
this.timeInterval = Math.max(1000, this.options.timeInterval);
this.maxTime = Math.max(this.options.maxTime, 10000);
} else {
this.options = defaults;
}
if(this.options.autoStart === true) this.start()
// Utility method to extend defaults with user options
}
function extendDefaults(source, properties) {
var property;
for (property in properties) {
if (properties.hasOwnProperty(property)) {
source[property] = properties[property];
}
}
return source;
}
SleepTimer.prototype.start = function(){
var _ = this;
this.options.onStart()
this.curDate = Date.now();
this.timer = setInterval(function() {
_.newDate = Date.now();
var diff = _.newDate - _.curDate;
// for debugging
if(_.options.console && diff > _.timeInterval){
console.log('Your PC was idel for ' + diff / 1000 + 's of ' + _.maxTime /1000 + 's. TimeInterval is set to ' + _.timeInterval / 1000 + 's');
}
if (diff < _.maxTime) {
_.curDate = _.newDate;
} else {
_.options.onIdel();
// alert('You have been idle for ' + diff / 1000 + 's');
clearTimeout(_.timer);
}
}, this.timeInterval); // seconds
}
}());
var sleepTimer = new SleepTimer({
maxTime: 15000,
console: true,
onStart: function(){
console.log('sleepTimer started.');
},
onIdel: function(){
alert('Your session expired! Please login again.');
}
});
I have implemented the exact same requirement using AWS Cognito, with Lambda Authorizers, & Redis, I can't share the code at this stage but I can tell you everything how it is implemented with these components, the same concepts can be used with other non AWS components.
Firstly with implementing an inactivity logout, you will have to do it server side, as if somebody simply turns off their computer, the front-end website would not log them out. I used the concept of ACTIVE users. When users successfully authenticates, I store with a TTL of 15 minutes in Redis an entry with a key of their username & a value of ACTIVE (it can be username+sessionid if you want to allow multiple sessions for a given user at the same time).
In my custom Authorizers when a user is ACTIVE & they have a valid Token, I grant them access to the protected resource AND most importantly, I do another put in Redis with the username & ACTIVE.
Whenever the user logs out, I log them out in my identity management solution (Cognito) & I mark them as INACTIVE. Note that if a user does not hit the API within 15 minutes they will no longer have an entry of ACTIVE against their username and will not be able to access the API anymore & have to sign in again, for which they will be redirected to do.
There are many things to consider with this approach, for one thing often Authorizers cache results for some amount of time, and if say you cache the result for 5 minutes as an example, then you user might be logged off in 10 minutes as your user could hit the cache instead of the Authorizer which would not refresh the ACTIVE entry.
It's also important that you make sure whatever you use to store if a given user is ACTIVE is highly available and will recover quickly in the event of a failure.
The approach of using a cache store this way is similar to how token invalidation is retrofitted to stateless authorization protocols such as OAuth2.
We've been using this approach for a few months now, it seems to work fine for us, it can be a bit of an annoying requirement to handle, I'd had expected in AWS world that there would be a ready to use out of the box solution for this but there was none to speak of.

Javascript: How to speed up setTimeout function on website?

I am working on a website that asks me to complete a task, then once I complete that task it asks me to wait 1 hour before completing the next task.
What I am looking for here is to speed up the timer on this website instead of waiting for 1 hour.
How it works:
On Website I simply have to click on 'Roll' button then a timer start in descending order like (1:00)...(45:00)...(00:05) so on till it reach (00:00). Once it reach (00:00) it replace this timer to Roll button.
This timer only display Minutes and Second column.
It does not take computer time.
Changes I need:
Since it run in descending order or backward in seconds, I want to speedup this process so that instead of waiting for 1 hour I just have to wait for 20 or 30 minutes.
What I can't do:
Since this is a third party website so I cannot make changes in the website code I can only use browser console to run javascript code so I can override existing code on it.
Here is the Javascript for this timer:
<script>
$(function() {
$('#time_remaining').countdown({
until: +3600,
format: 'MS'
});
});
setTimeout(function() {
RefreshPageAfterFreePlayTimerEnds();
}, 3600 * 1000);
</script>
Looks like RefreshPageAfterFreePlayTimerEnds is global. So, you may try to override it like
var myTimeout = 3600; // 1 min
RefreshPageAfterFreePlayTimerEnds = function(speedUp) {
if(!speedUp) { // just to cancel "legal" call
return;
}
RefreshPageAfterFreePlayTimerEnds();
}
setTimeout(function(){ RefreshPageAfterFreePlayTimerEnds(true); }, myTimeout);
If you can't access to the website code, to change the code that doesn't allow you to reduce the time coding. You can change your IP address and use the website again.
If you have to sing in to use the website, forget, else you use another account and IP you will need to wait the time restricted to use again.

Capture user Idling using javascript

Our site has ifame links to different content sites which are used to do online exams
Some exams in the content pages are running 3+ hours
Also exam guard is there for prevent the users doing other stuff while doing the exams
The problem is that once user completed the exams over 3+hrs and come to the parent site (our site)
It has session time out issue in parent page, (Parent site session time out is set to 180min )
As a solution for this we have implemented following JQuery
var to;
$(document).ready(function () {
to = setTimeout("TimeOut()", 10000);
});
function TimeOut() {
$.ajax({ type: "POST",
url: "KeepAliveDummy.aspx", success: function () {
to = setTimeout("TimeOut()", 10000);
}
});
};
Now the problem is that if one user open Parent site and go away it will keep the session unwantedly,
Any suggestion for capture the idle time?
We can use "mousemove" event and see whether the user is active or not.
I have used the below code to test whether the user idle time reached the Maximum Idle time.
function checkIdleTimeOut() {
userIdleTime++;
if( userIdleTime >= maxIdleTime ) {
alert("Reached max User Idle Time");
clearInterval(intvl);
}
$("#output").html( "userIdleTime: " + userIdleTime );
}
I have provided a sample demo, where the max idle time is set to 5 seconds.
Demo at JSFiddle Demo

Is it possible to know how long a user has spent on a page?

Say I've a browser extension which runs JS pages the user visits.
Is there an "outLoad" event or something of the like to start counting and see how long the user has spent on a page?
I am assuming that your user opens a tab, browses some webpage, then goes to another webpage, comes back to the first tab etc. You want to calculate exact time spent by the user. Also note that a user might open a webpage and keep it running but just go away. Come back an hour later and then once again access the page. You would not want to count the time that he is away from computer as time spent on the webpage. For this, following code does a docus check every 5 minutes. Thus, your actual time might be off by 5 minutes granularity but you can adjust the interval to check focus as per your needs. Also note that a user might just stare at a video for more than 5 minutes in which case the following code will not count that. You would have to run intelligent code that checks if there is a flash running or something.
Here is what I do in the content script (using jQuery):
$(window).on('unload', window_unfocused);
$(window).on("focus", window_focused);
$(window).on("blur", window_unfocused);
setInterval(focus_check, 300 * 1000);
var start_focus_time = undefined;
var last_user_interaction = undefined;
function focus_check() {
if (start_focus_time != undefined) {
var curr_time = new Date();
//Lets just put it for 4.5 minutes
if((curr_time.getTime() - last_user_interaction.getTime()) > (270 * 1000)) {
//No interaction in this tab for last 5 minutes. Probably idle.
window_unfocused();
}
}
}
function window_focused(eo) {
last_user_interaction = new Date();
if (start_focus_time == undefined) {
start_focus_time = new Date();
}
}
function window_unfocused(eo) {
if (start_focus_time != undefined) {
var stop_focus_time = new Date();
var total_focus_time = stop_focus_time.getTime() - start_focus_time.getTime();
start_focus_time = undefined;
var message = {};
message.type = "time_spent";
message.domain = document.domain;
message.time_spent = total_focus_time;
chrome.extension.sendMessage("", message);
}
}
onbeforeunload should fit your request. It fires right before page resources are being unloaded (page closed).
<script type="text/javascript">
function send_data(){
$.ajax({
url:'something.php',
type:'POST',
data:{data to send},
success:function(data){
//get your time in response here
}
});
}
//insert this data in your data base and notice your timestamp
window.onload=function(){ send_data(); }
window.onbeforeunload=function(){ send_data(); }
</script>
Now calculate the difference in your time.you will get the time spent by user on a page.
For those interested, I've put some work into a small JavaScript library that times how long a user interacts with a web page. It has the added benefit of more accurately (not perfectly, though) tracking how long a user is actually interacting with the page. It ignore times that a user switches to different tabs, goes idle, minimizes the browser, etc.
Edit: I have updated the example to include the current API usage.
http://timemejs.com
An example of its usage:
Include in your page:
<script src="http://timemejs.com/timeme.min.js"></script>
<script type="text/javascript">
TimeMe.initialize({
currentPageName: "home-page", // page name
idleTimeoutInSeconds: 15 // time before user considered idle
});
</script>
If you want to report the times yourself to your backend:
xmlhttp=new XMLHttpRequest();
xmlhttp.open("POST","ENTER_URL_HERE",true);
xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
var timeSpentOnPage = TimeMe.getTimeOnCurrentPageInSeconds();
xmlhttp.send(timeSpentOnPage);
TimeMe.js also supports sending timing data via websockets, so you don't have to try to force a full http request into the document.onbeforeunload event.
The start_time is when the user first request the page and you get the end_time by firing an ajax notification to the server just before the user quits the page :
window.onbeforeunload = function () {
// Ajax request to record the page leaving event.
$.ajax({
url: "im_leaving.aspx", cache: false
});
};
also you have to keep the user session alive for users who stays long time on the same page (keep_alive.aspxcan be an empty page) :
var iconn = self.setInterval(
function () {
$.ajax({
url: "keep_alive.aspx", cache: false });
}
,300000
);
then, you can additionally get the time spent on the site, by checking (each time the user leaves a page) if he's navigating to an external page/domain.
Revisiting this question, I know this wouldn't be much help in a Chrome Ext env, but you could just open a websock that does nothing but ping every 1 second and then when the user quits, you know to a precision of 1 second how long they've spent on the site as the connection will die which you can escape however you want.
Try out active-timeout.js. It uses the Visibility API to check when the user has switched to another tab or has minimized the browser window.
With it, you can set up a counter that runs until a predicate function returns a falsy value:
ActiveTimeout.count(function (time) {
// `time` holds the active time passed up to this point.
return true; // runs indefinitely
});

Session time out using Javascript or jQuery

How can I redirect to the login page when the session has completed? The code should check that the user sits idle for some time and then does any other client side event. If it finds this condition, it should check the session time out, and if session completes, redirect to login page.
Checking for inactivity on a webpage will be like an attempt to listen multitude of event. This also means that if there is user interaction the a function (event handler) is going to be called quite a lot of times. If this handler/function is going to some ajax send/receive stuffs then it could ultimately make your user interface perform poorly.
Why not make the session expiration period short and auto log out the user after? That way if the user is truly active then most probably there will a request for a page within that time frame. You could also set up a timer based event which when fired will simply send dummy request to server to refresh the session as a way of letting the server know that the user is still active but just not ready to request another page yet. This would be the case where a user is editing a long text or something like that.
I hope it helps.
Session Logout after 5 minutes
<sctipt>
var interval;
$(document).on('mousemove', function () {
clearInterval(interval);
var coutdown = 5 * 60, $timer = $('.timer'); // After 6 minutes session expired (mouse button click code)
$timer.text(coutdown);
interval = setInterval(function () {
$timer.text(--coutdown);
if (coutdown === 0) {
alert("Session expired User successfully logout.");
window.location = "UserLogin.aspx";
}
}, 1000);
}).mousemove();
var interval;
$(document).on('keydown', function () {
clearInterval(interval);
var coutdown = 7 * 60, $timer = $('.timer'); // After 6 minutes session expired (keyboard button press code)
$timer.text(coutdown);
interval = setInterval(function () {
$timer.text(--coutdown);
if (coutdown === 0) {
alert("Session expired User successfully logout.");
window.location = "UserLogin.aspx";
}
}, 1000);
}).mousemove();
<sctipt>
<div class="timer">
Time of session display on page
</div>

Categories

Resources