package javango.contrib.jquery.widgets;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.Security;
import java.security.spec.KeySpec;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import javango.api.Settings;
import javango.contrib.jquery.JqueryWidget;
import javango.contrib.jquery.fields.JqueryLookupField;
import javango.contrib.jquery.widgets.JqueryLookupWidget.PBEEncryptDataString.EncryptionException;
import javango.forms.fields.BoundField;
import javango.forms.widgets.TextInputWidget;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import org.apache.commons.logging.LogFactory;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import com.google.inject.Inject;
public class JqueryLookupWidget extends TextInputWidget implements JqueryWidget {
public static class PBEEncryptDataString {
static {
Security.addProvider(new com.sun.crypto.provider.SunJCE());
}
static public class EncryptionException extends Exception
{
private EncryptionException(String text, Exception chain)
{
super(text, chain);
}
}
//private static final String ALGORITHM = "PBEWithMD5AndDes";
private static final String ALGORITHM = "PBEWithSHA1AndDESede";
//private static final String ALGORITHM = "PBEWithMD5AndTripleDES";
public PBEEncryptDataString(String passphrase, byte[] salt, int iterationCount, String characterEncoding) throws EncryptionException
{
assert(passphrase != null);
assert(passphrase.length() >= 6);
assert(salt != null);
assert(salt.length == 8);
assert((iterationCount > 6) && (iterationCount < 20));
assert(characterEncoding != null);
try
{
PBEParameterSpec params = new PBEParameterSpec(salt, iterationCount);
KeySpec keySpec = new PBEKeySpec(passphrase.toCharArray());
SecretKey key = SecretKeyFactory.getInstance(ALGORITHM, "SunJCE").generateSecret(keySpec);
this.characterEncoding = characterEncoding;
this.encryptCipher = Cipher.getInstance(ALGORITHM, "SunJCE");
this.encryptCipher.init(javax.crypto.Cipher.ENCRYPT_MODE, key, params);
this.decryptCipher = Cipher.getInstance(ALGORITHM, "SunJCE");
this.decryptCipher.init(javax.crypto.Cipher.DECRYPT_MODE, key, params);
}
catch (Exception e)
{
throw new EncryptionException("Problem constucting " + this.getClass().getName(), e);
}
}
synchronized public String encrypt(String dataString) throws EncryptionException
{
assert dataString != null;
try
{
byte[] dataStringBytes = dataString.getBytes(characterEncoding);
byte[] encryptedDataStringBytes = this.encryptCipher.doFinal(dataStringBytes);
String encodedEncryptedDataString = this.base64Encoder.encode(encryptedDataStringBytes);
return encodedEncryptedDataString;
}
catch (Exception e)
{
throw new EncryptionException("Problem encrypting string", e);
}
}
synchronized public String decrypt(String encodedEncryptedDataString) throws EncryptionException
{
assert encodedEncryptedDataString != null;
try
{
byte[] encryptedDataStringBytes = this.base64Decoder.decodeBuffer(encodedEncryptedDataString);
byte[] dataStringBytes = this.decryptCipher.doFinal(encryptedDataStringBytes);
String recoveredDataString = new String(dataStringBytes, characterEncoding);
return recoveredDataString;
}
catch (Exception e)
{
throw new EncryptionException("Problem decrypting string", e);
}
}
private String characterEncoding;
private Cipher encryptCipher;
private Cipher decryptCipher;
private BASE64Encoder base64Encoder = new BASE64Encoder();
private BASE64Decoder base64Decoder = new BASE64Decoder();
}
public static String encrypt(Map<String, String> params) {
try {
StringBuilder b = new StringBuilder();
for(Entry<String, String> e : params.entrySet()) {
b.append(e.getKey());
b.append("=");
b.append(e.getValue());
b.append(";");
}
String encryptedString = new PBEEncryptDataString("The Password", salt, 9, "UTF-8").encrypt(b.toString());
return encryptedString;
} catch (EncryptionException e) {
LogFactory.getLog(JqueryLookupWidget.class).error(e,e);
}
return null;
}
static final byte[] salt = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
public static Map<String, String> decrypt(String encryptedURL) throws EncryptionException, UnsupportedEncodingException {
// TODO Need the correct encoding settings maybe...
String encryptedString = encryptedURL;
// TODO need beter mtehod for passing the encryption provider... Guice anyone...
String result = new PBEEncryptDataString("The Password", salt, 9, "UTF-8").decrypt(encryptedString);
Map<String, String> resultMap = new HashMap<String, String>();
for(String pair : result.split(";")) {
String[] v = pair.split("=");
resultMap.put(v[0], v[1]);
}
return resultMap;
}
public String getScript(BoundField field) {
try {
if (!field.getField().isEditable()) return "";
if (field.getField() instanceof JqueryLookupField) {
JqueryLookupField lookupField = (JqueryLookupField) field.getField();
// TODO Need to get the form's id property for the format
// maybe from the Field's attr map
String fieldId = String.format("id_%s", field.getHtmlName());
Map<String, String> urlParameters = new HashMap<String, String>();
urlParameters.put("model", lookupField.getModel().getCanonicalName());
urlParameters.put("display", lookupField.getDisplay());
urlParameters.put("search", lookupField.getSearch());
urlParameters.put("results", lookupField.getResults());
urlParameters.put("field", fieldId);
if (lookupField.getOrderBy() != null) urlParameters.put("order_by", lookupField.getOrderBy());
return String.format(
"$('#%1$s').javangoLookupWidget('%2$s', '%3$s');",
fieldId, // 1 TODO not correct, should use ID
URLEncoder.encode(encrypt(urlParameters), "UTF-8"), // 2
settings.get("jquery_media_url") // 3
);
}
return "<!-- " + field.getHtmlName() + " not a JqueryLookupField -->";
} catch (UnsupportedEncodingException e) {
LogFactory.getLog(JqueryLookupWidget.class).error(e,e);
return "<!-- " + field.getHtmlName() + e + " -->";
}
}
Settings settings;
@Inject
public JqueryLookupWidget(Settings settings) {
super();
this.settings = settings;
}
@Override
public String render(String name, Object value, Map<String, Object> attrs) {
return String.format("%3$s",
name, // 1
settings.get("jquery_media_url"), // 2
super.render(name, value, attrs)); // 3
}
}