简体   繁体   中英

Hide background-image inline styling from source code

I needed to create a simple memory game for a course I'm attending and I came up with this:

Simple memory game

$(document).ready(function(){

    // Set initial time to 0
    var currentTime = 0;
    // Set initial score to 0
    var score = 0;
    // Set initial attempt to 0
    var attempts = 0;
    // Placeholder
    var timeHolder;

    // Start the game when clicking the button #start
    $('#start').on('click', init);  

    // Check if user hasn't clicked #start button yet
    $('.board_cell').on('click.initialCheck', checkInitial);        

    function init() {

        // Shuffle elements at beginning
        shuffle();

        // Handle click event and check if elements match
        $('.board_cell').on('click', checkAccuracy).off('click.initialCheck');

        $('#start').off('click', init); 

        $('#reset').on('click', reset);

        // stop timer
        clearInterval(timeHolder)           

        // Timer function will be called every 100ms
        timeHolder = window.setInterval(timer, 100);
    }

    /*
         * Main function to handle click events and do actions
         * @checkAccuracy
         */

        function checkAccuracy() {
            var self = $(this),
                allElements = $('.board_cell'),
                // Url of background-image
                bgUrl = self.children('.back').css('background-image'),
                // Get relevant part (the image name) from the url
                elementType = bgUrl.slice(bgUrl.lastIndexOf('/') + 1, bgUrl.lastIndexOf('.'));

            // Flip the clicked element
            self.addClass('flipped ' + elementType);

            // Check if clicked element is already visible
            if (self.hasClass('success')) {
                showMessage('Das ist schon aufgedeckt ;)');

                // Abort function by returning false
                return false;
            }

            if($('.flipped').length >= 2) {
                // Prevent clicking on other elements when 2 elements are already visible
                allElements.off('click');
                // Increase attempts
                attempts++; 
                setAttempts();              
            }

            if($('.'+elementType).length == 2) {
                // If the same are visible
                score++;
                setScore();
                showMessage(['That was a right one!!!', 'Now you got it!', 'Terrific!']);   
                toggleClasses('success', function(){
                    // Callback when toggleClasses has finsihed

                    if($('.success').length == allElements.length){
                        // If alle elements are visible

                        showMessage('Everything exposed, congrats!');
                        $('#overlay').fadeIn();
                        // Kill interval to prevent further increasing
                        clearInterval(timeHolder);
                    }           
                });

            } else {
                // If they are not the same
                if($('.flipped').length == 2) {
                    toggleClasses();
                    showMessage(['Uhh that was wrong...', 'Are you drunk?', 'Try it again...', 'You better stop playing!',
                                 'Seems like you need to train much more...', 'Annoying?', 'C\'mon!']);
                }
            }           
        }

        /*
         * Function to reset the game
         */

        function reset() {
            // turn elements and prevent clicking
            $('.board_cell').removeClass('success flipped').off('click');

            // hide overlay if visible
            if($('#overlay').is(':visible')) {
                $('#overlay').fadeOut();
            }

            // stop timer
            clearInterval(timeHolder)

            // set time to 0
            currentTime = 0;

            // set attempts to 0
            attempts = 0;
            setAttempts();

            // set score to 0
            score = 0;
            setScore(); 

            // hide message
            showMessage('');

            // set visible time to 0
            $('#time span').text(currentTime);

            // Check if user has clicked #start button
            $('.board_cell').on('click.initialCheck', checkInitial);

            $('#start').on('click', init);          
        }

        /*
         * Function to show a message
         */         

        function showMessage(msg) {
            if(typeof msg == 'object') {
                var randomNumber = Math.floor((Math.random()*msg.length)+1);
                msg = msg[randomNumber-1];
            }

            $('#message span').html(msg);
        }

        /*
         * Function to toggleClasses on clickable elements
         */         

        function toggleClasses(extraClass, callback) {
            setTimeout(function(){
                $('.flipped').removeClass().addClass('board_cell '+extraClass);
                $('.board_cell').on('click', checkAccuracy);

                if(typeof callback != 'undefined') {
                    callback();
                }                       
            }, 1000);
        }

        /*
         * Function to increase score
         */             

        function setScore() {
            $('#score span').text(score);
        }

        /*
         * Function to increase attempts
         */             

        function setAttempts() {
            $('#attempts span').text(attempts);
        }       

        /*
         * Function for timer
         */                 

        function timer() {
            currentTime = currentTime + 1;

            $('#time span').text(currentTime/10);
        }

        /*
         * Function for showing message when user hasn't clicked #start button yet
         */                 

        function checkInitial() {
            showMessage('You need to press the "Start Game" button to beginn');
        }           

        /*
         * Function for shuffling elements
         */                 

        function shuffle() {
            var elementsArray = [];

            $('.back').each(function(index){
                elementsArray.push($(this).css('background-image'))
            });

            elementsArray.sort(function() {return 0.5 - Math.random()})

            $('.back').each(function(index){
                $(this).css('background-image', elementsArray[index]);
            });         
        }       
    });

The hidden images are added through inline styling with background-image and are shuffled on each start/reset but that doesn't prevent a user to cheat during the game (looking at the source code tells the solution immediately).

I'd like to know if there is a way to hide the background-image value in the source code? I tried some base64 encryption but as the browser interprets this immediately it doesn't serve at all. Another idea I had was to encrypt the background-image with php , display a random output (which was saved in a database for instance) in the markup and communicate through ajax requests with the php file on each click event. I'm not sure if this works, but anyway it seems like a circuitous way of handling it..

Any suggestion on how to solve this in safe and efficient way?

A safe (and overkill) solution would be to do this entirely serverside. Start a new game by generating a random session id and shuffling the squares. Then, your clientside JS requests the square images through AJAX via some sort of API:

GET /<session_id>/square/<x>/<y>

Once you rate limit the requests serverside to prevent a user from downloading all of the images at once, your game is safe.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM