stop Chrome from restoring the session - javascript

Is there any way to tell chrome to NOT restore the session when re-opening a closed page? Maybe a special header?
When my employees log into my company app it is very state dependant. If they are inactive for 60 minutes I want to log them out and delete all data relevant to what they were doing, but the problem is that Chome has this handy feature where it will re-open your page right where you left off and not question a thing. My website will not know that they had the browser closed for two days and the setTimeout will not fire for another 50 minutes.
I have another couple of wacky workarounds, but I would prefer it if I could just tell Chrome to not try salvaging old sessions and instead treat every opening like it was just opened for the first time. maybe a disable caching through javascript?
Edit:
I am using IIS to serve the Angular 9 static html and javascript.

So, as you mentioned, you're using a static website without a backend. Though you haven't mentioned anything, I'm assuming you're using sessionStorage or localStorage to handle authentication. If that's the case, what you can do is set a timer whenever a user logs in and maintain a localStorage to keep track of the idle time.
let obj_date = new Date();
let miliseconds = obj_date.getTime(); // Returns the number of miliseconds since 1970/01/01
localStorage.setItem("idle_time",miliseconds);
After that, keep calling the following function from within something like setInterval() every 10,20,30 or 60 seconds (as per your choice) to check if that time limit has expired.
function check_if_session_expired() {
let max_idle_minutes=60;
let miliseconds_now = obj_date.getTime();
let get_idle_time_in_miliseconds = localStorage.getItem("idle_time");
let one_minute_to_milisecond = 1000 * 60;
if ((Math.round(miliseconds_now / one_minute_to_milisecond) - Math.round(get_idle_time_in_miliseconds / one_minute_to_milisecond)) >= max_idle_minutes) {
console.log("expired");
//logout the user and clear sessionStorage/localStorage if you want
} else {
localStorage.setItem("idle_time",miliseconds_now);
}
}
You can use cookies to so the same.

What you want to do is destroy session from server side. Check the code below which is written in php. However, if you get the idea, you can use anything to implement it.
<?php
session_start();
//Expire the session if user is inactive for 60 minutes or more.
$expireAfter = 60;
//Assign the current timestamp as the user's latest activity
$_SESSION['last_action'] = time();
//Check to see if our "last action" session variable has been set.
if(isset($_SESSION['last_action'])){
//Figure out how many seconds have passed since the user was last active.
$secondsInactive = time() - $_SESSION['last_action'];
//Convert our minutes into seconds.
$expireAfterSeconds = $expireAfter * 60;
//Check to see if they have been inactive for too long.
if($secondsInactive >= $expireAfterSeconds){
//User has been inactive for too long. Kill their session.
session_destroy();
unset($_SESSION);
header("Location: http://".$_SERVER['SERVER_NAME'].":".$_SERVER['SERVER_PORT']."/example/login.php");
exit;
}
}
This is just a simple implementation and you can definitely extend it to make it work the way you want.

Related

Keep the JS/jQuery code working in Safari when the tab is not active

I have a JS/jQuery code as shown below in which in which I want to keep the JS/jQuery code working when the session tab is not active.
The following code perfectly fine in Google Chrome but it doesn't work in Safari.
jQuery(document).ready(function ($) {
let lastActivity = <?php echo time(); ?>; // Line A
let now = <?php echo time(); ?>;
let logoutAfter = 3600; // page will logout after 1800 seconds if there is no activity
let userName = "<?php echo $_SESSION['user_name']; ?>";
let timer = setInterval(function () {
now++;
let delta = now - lastActivity;
console.log(delta); // Line A
if (delta > logoutAfter) {
clearInterval(timer);
//DO AJAX REQUEST TO close.php
$.ajax({
url: "/control/admin.php",
type: 'GET', // GET also fine
data: {action: 'logout', user_name: userName},
success: function (data) {
window.location.href = "admin.php";
},
error: function (jqXHR, textStatus, errorThrown) {
alert(textStatus);
}
});
}
}, 1000); //<-- you can increase it( till <= logoutAfter ) for better performance as suggested by #"Space Coding"
});
The value at Line A doesn't get incremented in Safari when the tab is not active but it works perfectly fine in Google Chrome. In Google Chrome, it works as expected.
You can replace counter (it counts seconds) with calculating time difference.
let lastActivity = new Date();
let logoutAfter = 3600;
...
let delta = (new Date()).getTime() - lastActivity.getTime();
if (delta > logoutAfter) {
...
}
P.S. So it must work even if the script itself is frozen when tab is inactive. Interval handler will be called at the moment when user activate this tab.
This approach will not work properly with multiple tabs opened. If user open new tab and started working in it, the earlier tab will logout the user as he is not active in that tab.
To overcome this, I will suggest to check the last active time from server using ajax call instead of doing it with javascript only.
According to this very thorough (but old) answer, setInterval() execution on inactive tabs is limited to max 1/s, on both Safari and Chrome - but not stopped. There are also plenty of questions here on SO about Javascript getting paused or de-prioritised on inactive tabs, some of which include solutions:
How can I make setInterval also work when a tab is inactive in Chrome?
iOS 5 pauses JavaScript when tab is not active
Safari JavaScript setTimeout stops when minimized
Chrome: timeouts/interval suspended in background tabs?
Probably the best option to do what you are trying is to use Web workers:
Web Workers are a simple means for web content to run scripts in background threads. The worker thread can perform tasks without interfering with the user interface.
There is an example of how to do that in an answer to one of the questions above.
But there is also a much simpler option, though you should evaluate if it is safe considering you are relying on this to log users out.
My testing of your code reflects the question I linked to earlier which describes setInterval() being slowed, but not stopped. For me, Safari (v 13.1, macOS 10.14.6) does not actually fully pause Javascript, but slows down execution of the loop, by increasing amounts. I see this by opening the dev console, and watching the output of the console.log(delta) messages - they slow right down, first running only every 2s, then 4s, and so on, though sometimes faster. But they do not stop.
That output also gives a hint about the problem, and the solution. The delta values shown on the console do not represent the real time difference since lastActivity. They are just incrementing numbers. If you see a delta value appear on the console 10 seconds after the last one, it should logically be +10, right? But it is not, it is just one higher.
And that's the problem here - the code is not counting the true time difference, it is just counting iterations of the loop:
let timer = setInterval(function () {
now++; // <-- problem
This code correctly sets now to the current time only if setInterval() runs exactly every second. But we know that when the tab is inactive, it does not. In that case it is just counting the number of times the loop runs, which has no relation to the real time elapsed.
To solve this problem, we have to determine now based on the real time. To do that, let's switch to using JS to calculate our timestamps (PHP is rendered only once, on page load, so if you use it inside the loop it will just stay fixed at the initial value):
// Note that JS gives us milliseconds, not seconds
let lastActivity = Date.now();
let now = Date.now();
let logoutAfter = 3600 * 1000;
let timer = setInterval(function () {
// PHP won't work, time() is rendered only once, on page load
// let now = <?php echo time(); ?>;
now = Date.now();
let delta = now - lastActivity;
console.log('New timer loop, now:', now, '; delta:', delta);
Now, even if there is a pause of 10s between iterations, delta will be the true measure of time elapsed since the page was loaded. So even if the user switches away to another tab, every time the loop runs, it will correctly track time, even if it doesn't happen every second.
So what does this mean in your case?
According to your report, JS is not running at all in the inactive tab. In that case, it can happen that the tab stays in the logged-in state, long past the time the user should have been logged out. However, assuming JS starts up again when you switch back the tab, the very first iteration of the loop will correctly calculate the time elapsed. If it is greater than your logout period, you will be logged out. So even though the tab stayed logged in longer than it should have, the user can't use it, since as soon as they switch to it they will be logged out. Note that "as soon" actually means "within 1 second plus the time it takes for the AJAX query to successfully log the user out".
In my testing, JS does not stop in an inactive Safari tab, but slows right down. In this case, it would mean that the user would be automatically logged out on the inactive tab, though not right at the time they should be. If the loop runs say every 8s, it could mean that the user would be logged out up to 7s later than they should have been. If iterations slow down even more, the delay can potentially be even more. Assuming JS starts up again as normal as soon as the user switches back the tab, behaviour will be exactly as above, the first iteration in that case will log them out.
EDIT
Here's simplified, complete code, and a JSFiddle showing it running and working.
jQuery(document).ready(function($) {
let lastActivity = Date.now();
let now = Date.now();
let logoutAfter = 3600 * 1000;
let timer = setInterval(function() {
now = Date.now();
let delta = now - lastActivity;
console.log('New timer loop, now:', now, '; delta:', delta);
if (delta > logoutAfter) {
alert('logout!');
}
}, 1000);
});

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.

Keep track of a timer even when the user isn't on the page

At the moment, I have a simple signup and login PHP system going,
I want to achieve a little timer which the user can set up for their personal use, I was wondering if they could type in something like 12 hours and then a timer would count down until that timer ran out and they could start it again, I was thinking the timer could keep going even when they don't have the page loaded, so I was thinking it needed to be stored in a mySQL database, I am just having great difficulty with this and I hope I'm not asking for too much.
Thank you for your time in advance.
The following will probably work but requires a system which has crontab (could work in windows with a task scheduler but the syntax would be different).
Create a table:
UserTimers
----------
user_id | timer_id | trigger_time
When a user creates a timer add it to this table.
Create an executable PHP script (say it's stored at /etc/cronmgr)
#!/usr/bin/php
<?php
$rows = mysqli_query("SELECT * FROM UserTimers WHERE trigger_time <= NOW()"); // Timer should have been triggered by now
//Get all rows and do whatever you need to do with them
mysqli_query("DELETE FROM UserTimers WHERE trigger_time <= NOW()");
Add the following line in your crontab:
*/2 * * * * /etc/cronmgr
This will run your cronmgr script every 2 minutes (adjust if you think there's going to be too much server load).
However a user's timer may be off by X minutes (where X is the interval, i.e. 2 in this example) so if a user asks for a timer of 1 minute, that won't work as well.

How I can display a banner that changes every 10 seconds and respect the period while the page refreshes?

I am developing a builder of advertising campaigns on js and php that displays a banner every 10 seconds with setInterval function of javascript, but when the site refreshes the setInterval restarts. if you refresh the page in less than 10 seconds it will always display the same banner.
Is there a way to maintain a setInterval function in the server side, or something?
I'm trying this with javascript storing each second on a localStorage (HTML5) to continue in the same second when you refresh the page, but I think that is not the way to do it.
I hope someone will help me to jump this hurdle that has breaking my head. :)
You need to persist the state of the interval timer somewhere, either on the server or on the client. Local storage sounds like one option. Other options would be a cookie, a url parameter, or a form parameter if you are using HTTP post.
Is there a way to maintain a setInterval function in the server side, or something?
You say you're using PHP, so just use a PHP session to record when the last banner was loaded. If you get another call and the session time is <10 seconds ago then serve the same banner, otherwise serve a new one.
Yes, you'll still need a 10 second timer in JavaScript to trigger the banner to refresh, but you don't need all that stuff with localStorage -- it sounds like you're overthinking a really simple problem.
You can store your timer in a session which will only update every ten seconds
<?php
if (!isset($_SESSION)) {
session_start();
}
$time = time();
echo $time.'<br>';
$interval = 10; // ten seconds
if(!isset($_SESSION['timer']) || $_SESSION['timer'] == '') { // if the timer has not been started
$_SESSION['timer'] = $time; // sets the timer to start now
echo 'start timer = '.$_SESSION['timer'].'<br>';
} else { // the timer has already been started
echo 'timer = '.$_SESSION['timer'].'<br>';
if(($_SESSION['timer'] + $interval) < $time) {
// get new banner
echo 'get new banner<br>';
$_SESSION['timer'] = $time; // start the timer again
} else {
echo 'not yet';
}
}
?>
Try running this code and refresh the page every second... you will see "get new banner" only every ten seconds. Otherwise you will see "not yet".
You can put your code to get the new banner here `// get new banner'

Control duration of the session PHP

I am very beginner in web development. I spent some time realizing the way to limit session time in PHP. I have read Stackoverflow suggestions but none of them seems to work for me (cookies-might be edited by user, AJAX communication-extra load on server and static PHP - what about passive tabs in browser? Validation using session vars).
I have in mind this:
<script type="text/javascript">
$(document).ready(function() {
setTimeout(function() {
window.location.href = 'logout.php';
}, 10000);
});
</script>
...to limit session time for users. This system will be used in a management web app. Could anyone point out potential drawbacks of my approach, because it seems to be too simple to be good?
<?php
function check_user_is_valid () {
//Start our session.
session_start();
//Expire the session if user is inactive for 30
//minutes or more.
$expireAfter = 30;
//Check to see if our "last action" session
//variable has been set.
if(isset($_SESSION['last_action'])){
//Figure out how many seconds have passed
//since the user was last active.
$secondsInactive = time()-$_SESSION['last_action'];
//Convert our minutes into seconds.
$expireAfterSeconds = $expireAfter * 60;
//Check to see if they have been inactive for too long.
if($secondsInactive >= $expireAfterSeconds){
//User has been inactive for too long.
//Kill their session.
session_unset();
session_destroy();
}
}
}
//Assign the current timestamp as the user's
//latest activity
$_SESSION['last_action'] = time();
Call check_user_is_valid () function on every php page to check if the user have valid session.It will automatically destroy session if page is still for 30 minutes.
Update the value of $_SESSION['last_login'] variable with new time on every page, so that the user get 30 minutes session for each and every page.

Categories

Resources