-
package com.threeleaf.jsf.components.formsignature;
-
-
import java.security.MessageDigest;
-
import java.text.SimpleDateFormat;
-
import java.util.Calendar;
-
import java.util.Date;
-
-
import javax.faces.application.FacesMessage;
-
import javax.faces.component.UIComponent;
-
import javax.faces.context.FacesContext;
-
import javax.faces.validator.Validator;
-
import javax.faces.validator.ValidatorException;
-
import javax.servlet.ServletContext;
-
-
import org.apache.log4j.Logger;
-
-
import com.threeleaf.agentguidedselling.model.StringEncrypter;
-
import com.threeleaf.agentguidedselling.model.StringEncrypter.EncryptionException;
-
-
/**
-
* Add a "random" but verifiable form field in Faces to prevent many kinds of
-
* scripted spam attacks. The idea is to tie a browser session to a web address
-
* during a given timeframe. The goal is to make sure that 1) no generated
-
* script will be valid for more than an hour 2) robots to different machines
-
* cannot be spawned. The technique can be worked around, but the hope is that
-
* spammers will not find it worth their while to do so. If stronger prevention
-
* is needed, then captchas can be used.
-
*
-
* @author John A. Marsh
-
*
-
*/
-
public class FormSignatureValidator implements Validator {
-
private Logger logger = Logger.getLogger(this.getClass().getName());
-
-
/*
-
* Generates the variable to be used in the form signature input tag. The
-
* value changes every hour. It is assumed
-
* that no single form will ever take an hour to fill out and submit. Every
-
* hour, the length of the random variable will change. The object is to
-
* twart script robots. It is not perfect, but it works well without
-
* requiring captchas.
-
*
-
* @param optional calendar object with which to calculate the field.
-
* Overloaded to default to the current time.
-
*
-
* @return a reproducable "random" string to be used as a form field name.
-
*
-
* @author John A. Marsh
-
*
-
*/
-
-
// The filed name will change once an hour
-
-
String fieldName = formatter.
format(now.
getTime());
-
// We want to have the string be between 7 and 14 characters in a
-
// reproducably "random" manner
-
int stringLength = 7 + fieldName.length() % 7;
-
fieldName = md5(fieldName);
-
/*
-
* We want the first character to begin with a letter, not a number, to
-
* guarantee browser and language compatibilty We want to start as close
-
* to the beginning as possible. It is highly improbably that one of the
-
* hex letters would not be found closer to the beginning than the first
-
* calculation, but it is there just in case.
-
*/
-
int firstCharacter = 31 - stringLength;
-
if (fieldName.indexOf("a")> -1)
-
firstCharacter =
Math.
min(firstCharacter, fieldName.
indexOf("a"));
-
if (fieldName.indexOf("b")> -1)
-
firstCharacter =
Math.
min(firstCharacter, fieldName.
indexOf("b"));
-
if (fieldName.indexOf("c")> -1)
-
firstCharacter =
Math.
min(firstCharacter, fieldName.
indexOf("c"));
-
if (fieldName.indexOf("d")> -1)
-
firstCharacter =
Math.
min(firstCharacter, fieldName.
indexOf("d"));
-
if (fieldName.indexOf("e")> -1)
-
firstCharacter =
Math.
min(firstCharacter, fieldName.
indexOf("e"));
-
if (fieldName.indexOf("f")> -1)
-
firstCharacter =
Math.
min(firstCharacter, fieldName.
indexOf("f"));
-
fieldName = fieldName.substring(firstCharacter, firstCharacter + stringLength);
-
return fieldName;
-
}
-
-
public static String formSignatureID
() {
-
-
return formSignatureID(now);
-
}
-
-
/*
-
* Create a form signature. This is basically a timestamp. The time in
-
* milliseconds is hashed and then paired with the encrypted value. On the
-
* other side, the time is unencrypted and compared with the hashed value.
-
*
-
* @param seed Optional "password" for the form
-
*
-
* @return the generated key
-
*
-
* @trows EncryptionException
-
*
-
* @author John A. Marsh
-
*
-
*/
-
public static String formSignatureGenerate
(String seed
) throws EncryptionException
{
-
Logger logger = Logger.getLogger("FormSignatureValidator.formSignatureGenerate(\"" + seed + "\")");
-
-
String millitime =
Long.
toString(currentDate.
getTime());
-
StringEncrypter encrypter = new StringEncrypter("DES", seed);
-
if(logger.isDebugEnabled()) {
-
logger.debug("Time in milliseconds: " + millitime);
-
logger.debug("md5(millitime): " + md5(millitime));
-
logger.debug("encrypter.encrypt(millitime): " + encrypter.encrypt(millitime));
-
}
-
return md5(millitime) + encrypter.encrypt(millitime);
-
}
-
-
public static String formSignatureGenerate
() {
-
ServletContext context = (ServletContext) FacesContext.getCurrentInstance().getExternalContext().getContext();
-
Logger logger = Logger.getLogger("FormSignatureValidator.formSignatureGenerate()");
-
String seed = context.
getServerInfo();
-
logger.debug("Generated seed: " + seed);
-
try {
-
return formSignatureGenerate(seed);
-
} catch (EncryptionException e) {
-
return "error";
-
}
-
}
-
-
-
try {
-
-
md.update(string.getBytes());
-
byte[] digest = md.digest();
-
String hexString = hexify
(digest
);
-
return hexString;
-
-
e.printStackTrace();
-
return null;
-
}
-
}
-
-
static private String[] HEX =
{ "0",
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"a",
"b",
"c",
"d",
"e",
"f" };
-
-
static public String hexify
(byte byValue
) {
-
int nValue = (int) byValue + 128;
-
return HEX[nValue / 16] + HEX[nValue % 16];
-
}
-
-
static public String hexify
(byte[] bytes
) {
-
-
for (int i = 0; i <bytes.length; i++) {
-
hexed += hexify(bytes[i]);
-
}
-
return hexed;
-
}
-
-
}