package jwebform.element;

import java.security.SecureRandom;
import java.util.Base64;

import com.coverity.security.Escape;

import jwebform.element.structure.Element;
import jwebform.element.structure.ElementResult;
import jwebform.element.structure.HTMLProducer;
import jwebform.element.structure.PrepareInfos;
import jwebform.element.structure.ProducerInfos;
import jwebform.env.Env;
import jwebform.validation.ValidationResult;

// Form-Elmement, that provides XSRF protection
public class XSRFProtection implements Element {

  private final String TOKENNAME = "tokenname";
  private final String TOKENVAL = "tokenVal";

  private final SecureRandom random = new SecureRandom();

  private final boolean staticTokenName;

  public XSRFProtection() {
    this(false);
  }

  // do not use staticTokenname = true in runtim. Use it only for testing
  public XSRFProtection(boolean staticTokenName) {
    this.staticTokenName = staticTokenName;

  }

  private String getRandomValue() {
    final byte[] bytes = new byte[32];
    random.nextBytes(bytes);
    return Base64.getEncoder().encodeToString(bytes);
  }

  @Override
  public ElementResult prepare(PrepareInfos renderInfos) {
    Env env = renderInfos.getEnv();
    env.ensureSessionAvail();

    // ############ validation

    String name = renderInfos.getEnv().getRequest().getParameter(TOKENNAME);
    String xsrfVal = renderInfos.getEnv().getRequest().getParameter(TOKENVAL);

    ValidationResult tempValidationResult;

    boolean isSubmitted = renderInfos.getEnv().getRequest().isSubmitted(TOKENVAL);
    System.err.println("In sesion: " );
    boolean submittedValueEqualsSessionVal = isSubmitted ? xsrfVal.equals(renderInfos.getEnv().getSessionGet().getAttribute(name)) : false;
    
    if ( isSubmitted  
    		&& !submittedValueEqualsSessionVal
    		//&& !staticTokenName
    		) {
      tempValidationResult = ValidationResult.fail("formchecker.xsrf_problem");
    } else {
    	tempValidationResult = ValidationResult.ok();
    }


    name = "token-" + Math.random();
    xsrfVal = getRandomValue();
    env.getSessionSet().setAttribute(name, xsrfVal);
    
    // ###############

    // TODO: What happens, if session runs out and user want's a new code?

    // is firstrun - then generate a complete new token

    ElementResult result = new ElementResult("xsrf_protection", getRenderer(), tempValidationResult);

    return result; // no representation
  }
  
  public HTMLProducer getRenderer() {
	  return producerInfos -> {
		  StringBuilder tags = new StringBuilder();

	      String name = "token-" + (staticTokenName ? "" : Math.random());
	      String xsrfVal = (staticTokenName ? "static" : getRandomValue());

	      tags.append("<input type=\"hidden\" name=\"" + TOKENNAME + "\" value=\""
	          + Escape.htmlText(name) + "\">");
	      tags.append("<input type=\"hidden\" name=\"" + TOKENVAL + "\" value=\""
	          + Escape.htmlText(xsrfVal) + "\">\n");

	      String rendererdHtml = tags.toString();

	      String problemDescription = "";
	      if (!producerInfos.getElementResult().getValidationResult().isValid) {
	        problemDescription = "XSRF Problem!<br>"; // RFE: MAke this
	                                                  // nicer/configurable!
	      }
	      return problemDescription + rendererdHtml;
	  };
  }


}

@@ -1567,48 +1567,8 @@
 L);%0A
-    System.err.println(%22In sesion: %22 );%0A
     
@@ -1983,16 +1983,40 @@
 oken-%22 +
+ (staticTokenName ? %22%22 :
  Math.ra
@@ -2021,16 +2021,17 @@
 random()
+)
 ;%0A    xs
@@ -2037,16 +2037,47 @@
 srfVal =
+  (staticTokenName ? %22static%22 :
  getRand
@@ -2085,16 +2085,17 @@
 mValue()
+)
 ;%0A    en
@@ -2379,16 +2379,29 @@
 enderer(
+name, xsrfVal
 ), tempV
@@ -2500,16 +2500,43 @@
 enderer(
+String name, String xsrfVal
 ) %7B%0A%09  r
@@ -2611,154 +2611,8 @@
 );%0A%0A
-%09      String name = %22token-%22 + (staticTokenName ? %22%22 : Math.random());%0A%09      String xsrfVal = (staticTokenName ? %22static%22 : getRandomValue());%0A%0A
 %09   

fix xsrf protection in real usage