Search code examples
jqueryspring-mvcscreenshot

Proof of display


I was asked to implement a "proof of display" in a web application...

This means that I need to, somehow, get a screenshot of what is or will be displayed (or close) to the client in his browser, to be able to prove that we did give him what he was needed as a "legal" evidence.

Even if I don't agree with this kind of proof (browser have their own way to display HTML, stored screenshot can easily be hack or faked, ...), I wonder if it has already been done somewhere and how to implement this kind of functionality.

Any Idea or experience ?

To make it simpler, we cannot ask user to install anything (plug-ins, applications, ...)
Technologies used : mainly Java, Spring-mvc, Thymeleaf and JQuery


Solution

  • OK, here are 2 solutions found :

    One server side : capture the HTML flow before sending it to the client's browser using Filter :

        public class ProofDisplayFilter implements Filter {
            @Override
            public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws ServletException {
    
                 HttpServletRequest request = (HttpServletRequest) req;
                 HttpServletResponse response = (HttpServletResponse) res;  
    
                 Mywriter writer = ...;
                 ProofWriter proofWriter = new ProofWriter(response.getWriter(), writer);
    
                  //doFilter will right in the proofWriter that will copy output flow
                  chain.doFilter(request, wrapResponse(response, proofWriter)); 
    
                  //do whatever you need with your copy
                  saveHTMLAndStaticContentAsZip(proofWriter);
            }
    
            private static HttpServletResponse wrapResponse (final HttpServletResponse response, final PrintWriter writer){
                    return new HttpServletResponseWrapper(response) {
                        public PrintWriter getWriter() throws IOException {
                            return writer;
                        }
                    };
           }
        }
    

    The thing is that you need to modify the HTML flow to get the good reference to js, css and image resources.

    One client side : (Thanks @NimChimpsky) use the html2canvas.js API to create a snapshot and send it to your controller as an image :

    JS

        html2canvas(document.body, {
                    onrendered: function(canvas) {
                        $.post('/myApp/proof',
                                {
                                    image : canvas.toDataURL()
                                },
                                function(data) {...});
                    }
                });
    

    CONTROLLER

        @RequestMapping(value = "/proof")
        @ResponseBody
        public void proof(@RequestParam(value="image") String imageBase64) throws IOException {
            long now = Calendar.getInstance().getTimeInMillis();
            byte[] bytes = imageBase64.replaceAll("data:image/.+;base64,", "").getBytes();
    
            File proof = new File("./proof", "display-"+now+".jpeg");
    
            if(!proof.exists()){
                Files.createParentDirs(proof);
            }
            Files.write(DECODER.decode(bytes), proof);
    }
    

    (Or anything else you need to do with this image)

    Both solutions have pros and cons :
    Server-side :
    PROS
    - Capture HTML as it is
    - possibility to process/compare HTML flow
    CONS
    - We don't know how it was displayed to the client
    - Consume a lot of disk space : ~1Mo/capture (need to save static files too)
    - What about part of the page called using AJAX ?

    client-side :
    PROS
    - Precise : set the script in the pages that need it
    - Manage rendering of the browser
    CONS
    - use HTML5 canvas which is not supported in IE until the 9th version.
    - Intrusive (in my point of view)

    Hoping this can help someonelse.
    Thanks for your support!