Prevent js alert() from pausing timers

后端 未结 8 851
花落未央
花落未央 2021-01-06 01:54

So I made some timers for a quiz. The thing is, I just realized when I put

javascript: alert(\"blah\");

in the address, the popup alert bo

8条回答
  •  别那么骄傲
    2021-01-06 02:04

    Ultimately, you cannot trust user input. Without keeping track of the time elapsed on the server, there's just no guarantee the data hasn't been manipulated.

    However, if you're confident your quiz-takers aren't JavaScript-savvy, and are merely relying on a "trick" they found somewhere, you could test for cheating (pausing) with the following code, which doesn't require modifying window.alert:

    var timer = {
        startDatetime: null,
        startSec: 0,
        variance: 1,
        exitOnPause: true,
        count: function (config) {
            var that = this;
    
            if (typeof config == "object" && typeof parseInt(config.seconds) == "number" && !isNaN(parseInt(config.seconds)))
            {
                if (typeof parseFloat(config.variance) == "number" && !isNaN(parseFloat(config.variance))) this.variance = config.variance;
                if (typeof config.exitOnPause == "boolean") this.exitOnPause = config.exitOnPause;
    
                if (config.seconds > 0)
                {
                    if (!this.startSec) this.startSec = config.seconds;
                    if (!this.startDatetime) this.startDatetime = new Date();
                    var currentDatetime = new Date();
    
                    if (currentDatetime.getTime() - this.startDatetime.getTime() > (this.startSec - config.seconds) * this.variance * 1000)
                    {
                        if (typeof config.onPause == "function") config.onPause();
    
                        if (!this.exitOnPause)
                        {
                            this.startDatetime = new Date();
                            this.startSec = config.seconds--;
                            window.setTimeout(function () { that.count(config); }, 1000);
                        }
                    }
                    else
                    {
                        config.seconds--;
                        window.setTimeout(function () { that.count(config); }, 1000);
                    }
                }
                else
                {
                    if (typeof config.onFinish == "function") config.onFinish();
                }
            }
        }
    };
    

    This timer object has a single method, count(), which accepts an object as input. It expects a seconds property in the input object at minimum.

    For some reason, window.setTimeout doesn't always work as expected. Sometimes, on my machine, window.setTimeout(x, 1000), which should execute the code after 1 second, took more than 2 seconds. So, in a case like this, you should allow a variance, so people who aren't cheating don't get flagged as cheaters. The variance defaults to 1, but it can be overridden in the input object. Here's an example of how to use this code, which allows 2.5 seconds of "wiggle room" for slow-pokes:

    timer.count({
        seconds: 10,
        onPause: function () { alert("You cheated!"); window.location.replace("cheatersAreBad.html"); },
        onFinish: function () { alert("Time's up!"); },
        variance: 2.5
    });
    

    With a solution like this, you could use Ajax to tell a server-side script that the user has paused the timer or redirect the user to a page explaining they were caught cheating, for example. If, for some reason, you wanted to allow the user to continue taking the quiz after they've been caught cheating, you could set exitOnPause to false:

    timer.count({
        seconds: 10,
        exitOnPause: false,
        onPause: function () { recordCheaterViaAjax(); },
        onFinish: function () { alert("Time's up!"); },
        variance: 2.5
    });
    

提交回复
热议问题