/* * File : $Source: /alkacon/cvs/alkacon/com.alkacon.opencms.formgenerator/src/com/alkacon/opencms/formgenerator/CmsCaptchaSettings.java,v $ * Date : $Date: 2010/12/07 17:02:24 $ * Version: $Revision: 1.11 $ * * This file is part of the Alkacon OpenCms Add-On Module Package * * Copyright (c) 2010 Alkacon Software GmbH (http://www.alkacon.com) * * The Alkacon OpenCms Add-On Module Package is free software: * you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * The Alkacon OpenCms Add-On Module Package is distributed * in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with the Alkacon OpenCms Add-On Module Package. * If not, see http://www.gnu.org/licenses/. * * For further information about Alkacon Software GmbH, please see the * company website: http://www.alkacon.com. * * For further information about OpenCms, please see the * project website: http://www.opencms.org. */ package com.alkacon.opencms.formgenerator; import org.opencms.file.CmsFile; import org.opencms.file.CmsObject; import org.opencms.i18n.CmsEncoder; import org.opencms.jsp.CmsJspActionElement; import org.opencms.main.CmsLog; import org.opencms.util.CmsRequestUtil; import org.opencms.util.CmsStringUtil; import org.opencms.xml.content.CmsXmlContent; import org.opencms.xml.content.CmsXmlContentFactory; import java.awt.Color; import java.security.Key; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import org.apache.commons.codec.binary.Base64; import org.apache.commons.fileupload.FileItem; import org.apache.commons.logging.Log; /** * Stores the settings to render captcha images.<p> * * @author Thomas Weckert * @author Achim Westermann * * @version $Revision: 1.11 $ * * @since 7.0.4 */ public final class CmsCaptchaSettings implements Cloneable { /** Request parameter for the background color. */ public static final String C_PARAM_BACKGROUND_COLOR = "bgcol"; /** Request parameter for the characters to use for generation. */ public static final String C_PARAM_CHARACTERS = "crs"; /** Request parameter for the encoded captcha data. */ public static final String C_PARAM_DATA = "data"; /** Request parameter for the dictionary file to use for generation. */ public static final String C_PARAM_DICTIONARY = "dict"; /** Request parameter for the filter amplitude. */ public static final String C_PARAM_FILTER_AMPLITUDE = "famplit"; /** Request parameter for the filter amplitude. */ public static final String C_PARAM_FILTER_WAVE_LENGTH = "fwavlen"; /** Request parameter for the font color. */ public static final String C_PARAM_FONT_COLOR = "fcol"; /** Request parameter for the font color. */ public static final String C_PARAM_HOLES_PER_GLYPH = "holes"; /** Request parameter for the image height. */ public static final String C_PARAM_IMAGE_HEIGHT = "h"; /** Request parameter for the image width. */ public static final String C_PARAM_IMAGE_WIDTH = "w"; /** Request parameter for the math flag to use for generation. */ public static final String C_PARAM_MATH = "math"; /** Request parameter for the max. font size. */ public static final String C_PARAM_MAX_FONT_SIZE = "maxfs"; /** Request parameter for the max phrase length. */ public static final String C_PARAM_MAX_PHRASE_LENGTH = "maxpl"; /** Request parameter for the min. font size. */ public static final String C_PARAM_MIN_FONT_SIZE = "minfs"; /** Request parameter for the min phrase length. */ public static final String C_PARAM_MIN_PHRASE_LENGTH = "minpl"; /** Request parameter for the min phrase length. */ public static final String C_PARAM_PRESET = "prst"; /** Request parameter for the min phrase length. */ public static final String C_PARAM_USE_BACKGROUND_IMAGE = "bgimg"; /** Configuration node name for the optional captcha background color. */ public static final String NODE_CAPTCHAPRESET_BACKGROUNDCOLOR = "BackgroundColor"; /** Configuration node name for the optional captcha character pool. */ public static final String NODE_CAPTCHAPRESET_CHARACTERS = "Characters"; /** Configuration node name for the optional captcha max. font size. */ public static final String NODE_CAPTCHAPRESET_DICTIONARY = "Dictionary"; /** Configuration node name for the field value node. */ public static final String NODE_CAPTCHAPRESET_FILTER_AMPLITUDE = "FilterAmplitude"; /** Configuration node name for the optional captcha image holes per glyph. */ public static final String NODE_CAPTCHAPRESET_FILTER_WAVELENGTH = "FilterWaveLength"; /** Configuration node name for the optional captcha font color. */ public static final String NODE_CAPTCHAPRESET_FONTCOLOR = "FontColor"; /** Configuration node name for the optional captcha image holes per glyph. */ public static final String NODE_CAPTCHAPRESET_HOLESPERGLYPH = "HolesPerGlyph"; /** Configuration node name for the optional captcha image height. */ public static final String NODE_CAPTCHAPRESET_IMAGEHEIGHT = "ImageHeight"; /** Configuration node name for the optional captcha image width. */ public static final String NODE_CAPTCHAPRESET_IMAGEWIDTH = "ImageWidth"; /** Configuration node name for the optional captcha math field flag. */ public static final String NODE_CAPTCHAPRESET_MATHFIELD = "MathField"; /** Configuration node name for the optional captcha max. font size. */ public static final String NODE_CAPTCHAPRESET_MAX_FONT_SIZE = "MaxFontSize"; /** Configuration node name for the optional captcha max. phrase length. */ public static final String NODE_CAPTCHAPRESET_MAX_PHRASE_LENGTH = "MaxPhraseLength"; /** Configuration node name for the optional captcha min. font size. */ public static final String NODE_CAPTCHAPRESET_MIN_FONT_SIZE = "MinFontSize"; /** Configuration node name for the optional captcha min. phrase length. */ public static final String NODE_CAPTCHAPRESET_MIN_PHRASE_LENGTH = "MinPhraseLength"; /** The encryption to be used. */ private static final String ENCRYPTION = "DES"; /** The format of the key and the values to be crypted. */ private static final String FORMAT = "UTF8"; /** The log object for this class. */ private static final Log LOG = CmsLog.getLog(CmsCaptchaSettings.class); /** The delimiter for the encrypted parameters. */ private static final String PARAM_DELIM = "&"; /** The key-value separator for the encrypted parameters. */ private static final String PARAM_KV_SEPARATOR = "="; /** The password to be used for encryption and decryption. */ private static final String PASSWORD = "oamp-9aX"; /** The the background color. */ private Color m_backgroundColor = Color.WHITE; /** The string containing the characters to use for word generation. */ private String m_characterPool = ""; /** The string containing the dictionary to use for word generation. */ private String m_dictionary; /** The filter amplitude for the water filter that bends the text. */ private int m_filterAmplitude = 2; /** The filter wave length for the water filter that bends the text. */ private int m_filterWaveLength = 100; /** The font color. */ private Color m_fontColor = Color.BLACK; /** The amount of holes per glyph. */ private Integer m_holesPerGlyph = new Integer(0); /** The image height in pixels. */ private int m_imageHeight = 55; /** The image width in pixels. */ private int m_imageWidth = 220; /** The math field flag. */ private boolean m_mathField; /** The maximum font size in pixels. */ private int m_maxFontSize = 40; /** The maximum phrase length. */ private int m_maxPhraseLength = 5; /** minimum font size in pixels. */ private int m_minFontSize = 30; /** The minimum phrase length. */ private int m_minPhraseLength = 5; /** The map of request parameters. */ private Map<String, String[]> m_parameterMap; /** * The path to the preset configuration (captchapreset) that has been used to initialize these * settings. This is read only, as the path is internally read from a nested CmsForm/FormCaptcha * XML content. */ private String m_presetPath = "factory_defaults_(classfile)"; /** The flag that decides wethter a background image or a background color is used. */ private boolean m_useBackgroundImage = true; /** * Private constructor for the clone method.<p> * * May only be called from {@link #clone()} as that method guarantees to install the default * value from the master captcha settings.<p> */ private CmsCaptchaSettings() { // nop } /** * Constructor that will use request parameters to init theses settings.<p> * * @param jsp the jsp context object */ private CmsCaptchaSettings(CmsJspActionElement jsp) { init(jsp); } /** * Returns a clone of the singleton instance of the * <em>"master"</em> <code>CmsCaptchaSettings</code> and potential overridden values from * the request context.<p> * * The <em>"master"</em> <code>CmsCaptchaSettings</code> are read from an XML content that * contains the global defaults.<p> * * @param jsp used to potentially access the XML content with the default captcha settings and * to read overriden values from the request parameters. * * @return a clone of the singleton instance of the * <em>"master"</em> <code>CmsCaptchaSettings</code>. */ public static CmsCaptchaSettings getInstance(CmsJspActionElement jsp) { CmsCaptchaSettings result = new CmsCaptchaSettings(jsp); return (CmsCaptchaSettings)result.clone(); } /** * Returns the background color.<p> * * @return the background color */ public Color getBackgroundColor() { return m_backgroundColor; } /** * Returns the background color as a hex string.<p> * * @return the background color as a hex string */ public String getBackgroundColorString() { StringBuffer buf = new StringBuffer(); buf.append("#"); buf.append(toHexString(m_backgroundColor.getRed())); buf.append(toHexString(m_backgroundColor.getGreen())); buf.append(toHexString(m_backgroundColor.getBlue())); return buf.toString(); } /** * Returns the dictionary for word generation.<p> * * @return the dictionary for word generation */ public String getDictionary() { return m_dictionary; } /** * Returns the filter amplitude for the water filter that bends the text.<p> * * @return the filter amplitude for the water filter that bends the text. */ public int getFilterAmplitude() { return m_filterAmplitude; } /** * Returns the filter wave length for the water filter that bends the text.<p> * * @return the filter wave length for the water filter that bends the text. */ public int getFilterWaveLength() { return m_filterWaveLength; } /** * Returns the font color.<p> * * @return the font color */ public Color getFontColor() { return m_fontColor; } /** * Returns the font color as a hex string.<p> * * @return the font color as a hex string */ public String getFontColorString() { StringBuffer buf = new StringBuffer(); buf.append("#"); buf.append(toHexString(m_fontColor.getRed())); buf.append(toHexString(m_fontColor.getGreen())); buf.append(toHexString(m_fontColor.getBlue())); return buf.toString(); } /** * Returns the holes per glyph for a captcha image text (distortion).<p> * * @return the holes per glyph for a captcha image text */ public Integer getHolesPerGlyph() { return m_holesPerGlyph; } /** * Returns the image height.<p> * * @return the image height */ public int getImageHeight() { return m_imageHeight; } /** * Returns the image width.<p> * * @return the image width */ public int getImageWidth() { return m_imageWidth; } /** * Returns the max. font size.<p> * * @return the max. font size */ public int getMaxFontSize() { return m_maxFontSize; } /** * Returns the max. phrase length.<p> * * @return the max. phrase length */ public int getMaxPhraseLength() { return m_maxPhraseLength; } /** * Returns the min. font size.<p> * * @return the min. font size */ public int getMinFontSize() { return m_minFontSize; } /** * Returns the min. phrase length.<p> * * @return the min. phrase length */ public int getMinPhraseLength() { return m_minPhraseLength; } /** * Configures the instance with values overridden from the the request parameters.<p> * * @param jsp a Cms JSP page * * @see #C_PARAM_BACKGROUND_COLOR * @see #C_PARAM_FILTER_AMPLITUDE */ public void init(CmsJspActionElement jsp) { List<FileItem> multipartFileItems = CmsRequestUtil.readMultipartFileItems(jsp.getRequest()); m_parameterMap = new HashMap<String, String[]>(); Map<String, String[]> parameters = new HashMap<String, String[]>(); if (multipartFileItems != null) { parameters = CmsRequestUtil.readParameterMapFromMultiPart( jsp.getRequestContext().getEncoding(), multipartFileItems); } else { parameters = jsp.getRequest().getParameterMap(); } if (parameters.containsKey(C_PARAM_DATA)) { // found encrypted data parameter, decrypt it String data = decrypt((parameters.get(C_PARAM_DATA))[0]); if (data != null) { // split the data into parameters Map<String, String> dataParameters = CmsStringUtil.splitAsMap(data, PARAM_DELIM, PARAM_KV_SEPARATOR); m_parameterMap = new HashMap<String, String[]>(dataParameters.size()); for (Iterator<Entry<String, String>> i = dataParameters.entrySet().iterator(); i.hasNext();) { // store values as String array Map.Entry<String, String> entry = i.next(); m_parameterMap.put(entry.getKey(), new String[] {entry.getValue()}); } } } else { // no encrypted parameters found, create empty map to use defaults m_parameterMap = new HashMap<String, String[]>(); } // image width String stringValue = getParameter(C_PARAM_IMAGE_WIDTH); if (CmsStringUtil.isNotEmpty(stringValue)) { m_imageWidth = Integer.parseInt(stringValue); } // image height stringValue = getParameter(C_PARAM_IMAGE_HEIGHT); if (CmsStringUtil.isNotEmpty(stringValue)) { m_imageHeight = Integer.parseInt(stringValue); } // min. phrase length stringValue = getParameter(C_PARAM_MIN_PHRASE_LENGTH); if (CmsStringUtil.isNotEmpty(stringValue)) { m_minPhraseLength = Integer.parseInt(stringValue); } // max. phrase length stringValue = getParameter(C_PARAM_MAX_PHRASE_LENGTH); if (CmsStringUtil.isNotEmpty(stringValue)) { m_maxPhraseLength = Integer.parseInt(stringValue); } // min. font size stringValue = getParameter(C_PARAM_MIN_FONT_SIZE); if (CmsStringUtil.isNotEmpty(stringValue)) { m_minFontSize = Integer.parseInt(stringValue); } // max. font size stringValue = getParameter(C_PARAM_MAX_FONT_SIZE); if (CmsStringUtil.isNotEmpty(stringValue)) { m_maxFontSize = Integer.parseInt(stringValue); } // font color stringValue = getParameter(C_PARAM_FONT_COLOR); if (CmsStringUtil.isNotEmpty(stringValue)) { stringValue = CmsEncoder.unescape(stringValue, jsp.getRequestContext().getEncoding()); setFontColor(stringValue); } // background color stringValue = getParameter(C_PARAM_BACKGROUND_COLOR); if (CmsStringUtil.isNotEmpty(stringValue)) { stringValue = CmsEncoder.unescape(stringValue, jsp.getRequestContext().getEncoding()); } setBackgroundColor(stringValue); // holes per glyph stringValue = getParameter(C_PARAM_HOLES_PER_GLYPH); if (CmsStringUtil.isNotEmpty(stringValue)) { setHolesPerGlyph(Integer.parseInt(stringValue)); } // filter amplitude stringValue = getParameter(C_PARAM_FILTER_AMPLITUDE); if (CmsStringUtil.isNotEmpty(stringValue)) { setFilterAmplitude(Integer.parseInt(stringValue)); } // filter wave length stringValue = getParameter(C_PARAM_FILTER_WAVE_LENGTH); if (CmsStringUtil.isNotEmpty(stringValue)) { setFilterWaveLength(Integer.parseInt(stringValue)); } // flag for generation of background image (vs. background color) stringValue = getParameter(C_PARAM_USE_BACKGROUND_IMAGE); if (CmsStringUtil.isNotEmpty(stringValue)) { setUseBackgroundImage(Boolean.valueOf(stringValue).booleanValue()); } // characters to use for word generation: stringValue = getParameter(C_PARAM_CHARACTERS); if (CmsStringUtil.isNotEmpty(stringValue)) { setCharacterPool(stringValue); } // dictionary to use for word generation: stringValue = getParameter(C_PARAM_DICTIONARY); if (CmsStringUtil.isNotEmpty(stringValue)) { setDictionary(stringValue); } // math field flag stringValue = getParameter(C_PARAM_MATH); if (CmsStringUtil.isNotEmpty(stringValue)) { setMathField(Boolean.valueOf(stringValue).booleanValue()); } // just for logging comfort (find misconfigured presets): stringValue = getParameter(C_PARAM_PRESET); if (CmsStringUtil.isNotEmpty(stringValue)) { m_presetPath = stringValue; } } /** * Configures the instance with overridden values from the given XML content.<p> * * <h3>Xmlcontent configuration notes</h3> * <ol> * <li> * <ul> * <li> If the xmlcontent contains no node for BackgroundColor ({@link CmsCaptchaSettings#NODE_CAPTCHAPRESET_BACKGROUNDCOLOR}), * a background image will be used. </li> * <li> If the xmlcontent node contains an empty node (trimmable to the empty String), the * default background colour {@link Color#WHITE}) will be used as background. </li> * <li> Else the chosen background color will be used. </li> * </ul> * </li> * </ol> * <p> * * @param cms the current user's Cms object * @param content the XML content of the form * @param locale the current locale */ public void init(CmsObject cms, CmsXmlContent content, Locale locale) { try { String captchaSettingsPath = CmsFormContentUtil.getContentStringValue(content, cms, new StringBuffer( CmsForm.NODE_CAPTCHA).append("/").append(CmsForm.NODE_CAPTCHA_PRESET).toString(), locale); if (CmsStringUtil.isNotEmpty(captchaSettingsPath)) { m_presetPath = captchaSettingsPath; CmsFile captchaSettingsFile = cms.readFile(captchaSettingsPath); CmsXmlContent preset = CmsXmlContentFactory.unmarshal(cms, captchaSettingsFile); Locale captchaSettingsLocale = Locale.ENGLISH; // image width String stringValue = preset.getStringValue( cms, CmsCaptchaSettings.NODE_CAPTCHAPRESET_IMAGEWIDTH, captchaSettingsLocale); if (CmsStringUtil.isNotEmpty(stringValue)) { m_imageWidth = Integer.parseInt(stringValue); } // image height stringValue = preset.getStringValue( cms, CmsCaptchaSettings.NODE_CAPTCHAPRESET_IMAGEHEIGHT, captchaSettingsLocale); if (CmsStringUtil.isNotEmpty(stringValue)) { m_imageHeight = Integer.parseInt(stringValue); } // min. phrase length stringValue = preset.getStringValue( cms, CmsCaptchaSettings.NODE_CAPTCHAPRESET_MIN_PHRASE_LENGTH, captchaSettingsLocale); if (CmsStringUtil.isNotEmpty(stringValue)) { m_minPhraseLength = Integer.parseInt(stringValue); } // max. phrase length stringValue = preset.getStringValue( cms, CmsCaptchaSettings.NODE_CAPTCHAPRESET_MAX_PHRASE_LENGTH, captchaSettingsLocale); if (CmsStringUtil.isNotEmpty(stringValue)) { m_maxPhraseLength = Integer.parseInt(stringValue); } // min. font size stringValue = preset.getStringValue( cms, CmsCaptchaSettings.NODE_CAPTCHAPRESET_MIN_FONT_SIZE, captchaSettingsLocale); if (CmsStringUtil.isNotEmpty(stringValue)) { m_minFontSize = Integer.parseInt(stringValue); } // max. font size stringValue = preset.getStringValue( cms, CmsCaptchaSettings.NODE_CAPTCHAPRESET_MAX_FONT_SIZE, captchaSettingsLocale); if (CmsStringUtil.isNotEmpty(stringValue)) { m_maxFontSize = Integer.parseInt(stringValue); } // font color stringValue = preset.getStringValue( cms, CmsCaptchaSettings.NODE_CAPTCHAPRESET_FONTCOLOR, captchaSettingsLocale); if (CmsStringUtil.isNotEmpty(stringValue)) { setFontColor(stringValue); } // background color // if the field is defined but left blank, the default background color will be used // if the field is not defined a gimpy background image will be used stringValue = preset.getStringValue( cms, CmsCaptchaSettings.NODE_CAPTCHAPRESET_BACKGROUNDCOLOR, captchaSettingsLocale); setBackgroundColor(stringValue); // holes per glyph stringValue = preset.getStringValue( cms, CmsCaptchaSettings.NODE_CAPTCHAPRESET_HOLESPERGLYPH, captchaSettingsLocale); if (CmsStringUtil.isNotEmpty(stringValue)) { setHolesPerGlyph(Integer.parseInt(stringValue)); } // filter amplitude stringValue = preset.getStringValue( cms, CmsCaptchaSettings.NODE_CAPTCHAPRESET_FILTER_AMPLITUDE, captchaSettingsLocale); if (CmsStringUtil.isNotEmpty(stringValue)) { setFilterAmplitude(Integer.parseInt(stringValue)); } // filter wave length stringValue = preset.getStringValue( cms, CmsCaptchaSettings.NODE_CAPTCHAPRESET_FILTER_WAVELENGTH, captchaSettingsLocale); if (CmsStringUtil.isNotEmpty(stringValue)) { setFilterWaveLength(Integer.parseInt(stringValue)); } stringValue = preset.getStringValue(cms, NODE_CAPTCHAPRESET_CHARACTERS, captchaSettingsLocale); if (CmsStringUtil.isNotEmpty(stringValue)) { setCharacterPool(stringValue); } stringValue = preset.getStringValue( cms, CmsCaptchaSettings.NODE_CAPTCHAPRESET_DICTIONARY, captchaSettingsLocale); if (CmsStringUtil.isNotEmpty(stringValue)) { setDictionary(stringValue); } // math field flag stringValue = preset.getStringValue(cms, NODE_CAPTCHAPRESET_MATHFIELD, captchaSettingsLocale); if (CmsStringUtil.isNotEmpty(stringValue)) { setMathField(Boolean.valueOf(stringValue).booleanValue()); } } else { // the optional preset selector is missing... } } catch (Exception ex) { if (LOG.isErrorEnabled()) { LOG.error(ex.getLocalizedMessage()); } } } /** * Returns the math field flag.<p> * * @return the math field flag */ public boolean isMathField() { return m_mathField; } /** * Returns the flag that decides wethter a background image or a background color is used.<p> * * @return the flag that decides wethter a background image or a background color is used */ public boolean isUseBackgroundImage() { return m_useBackgroundImage; } /** * Sets the background color.<p> * * @param backgroundColor the background color to set */ public void setBackgroundColor(Color backgroundColor) { m_backgroundColor = backgroundColor; } /** * Sets the background color as a hex string.<p> * * @param backgroundColor the background color to set as a hex string */ public void setBackgroundColor(String backgroundColor) { if (CmsStringUtil.isNotEmpty(backgroundColor)) { if (backgroundColor.startsWith("#")) { backgroundColor = backgroundColor.substring(1); } m_backgroundColor = new Color(Integer.valueOf(backgroundColor, 16).intValue()); m_useBackgroundImage = false; } else if (backgroundColor != null) { // not totally empty but consists of whitespaces only: use default value // this happens e.g. if the XML content to configure did contain the node but left the // value empty // in this case the default background color will be used m_useBackgroundImage = false; m_backgroundColor = Color.WHITE; } else { // really empty and null - not even defined in XML content: // don't use background color but a gimpy background image m_useBackgroundImage = true; // the color is not used but we have to avoid NPE in getBackgroundColorString() m_backgroundColor = Color.WHITE; } } /** * Sets the dictionary for word generation.<p> * * @param dictionary the dictionary to set */ public void setDictionary(String dictionary) { m_dictionary = dictionary; } /** * Sets the filter amplitude for the water filter that will bend the text.<p> * * @param i the filter amplitude for the water filter that will bend the text to set. */ public void setFilterAmplitude(int i) { m_filterAmplitude = i; } /** * Sets the filter wave length for the water filter that bends the text.<p> * * @param filterWaveLength the filter wave length for the water filter that bends the text to set */ public void setFilterWaveLength(int filterWaveLength) { m_filterWaveLength = filterWaveLength; } /** * Sets the font color.<p> * * @param fontColor the font color to set */ public void setFontColor(Color fontColor) { m_fontColor = fontColor; } /** * Sets the font color as a hex string.<p> * * @param fontColor the font color to set as a hex string */ public void setFontColor(String fontColor) { if (CmsStringUtil.isNotEmpty(fontColor)) { if (fontColor.startsWith("#")) { fontColor = fontColor.substring(1); } m_fontColor = new Color(Integer.valueOf(fontColor, 16).intValue()); } else { m_fontColor = Color.BLACK; } } /** * Sets the holes per glyph for a captcha image text (distortion).<p> * * @param holes the holes per glyph for a captcha image text to set. */ public void setHolesPerGlyph(int holes) { m_holesPerGlyph = new Integer(holes); } /** * Sets the image height.<p> * * @param imageHeight the image height to set */ public void setImageHeight(int imageHeight) { m_imageHeight = imageHeight; } /** * Sets the image width.<p> * * @param imageWidth the image width to set */ public void setImageWidth(int imageWidth) { m_imageWidth = imageWidth; } /** * Sets the math field flag.<p> * * @param mathField the math field flag */ public void setMathField(boolean mathField) { this.m_mathField = mathField; } /** * Sets the max. font size.<p> * * @param maxFontSize the max. font size to set */ public void setMaxFontSize(int maxFontSize) { m_maxFontSize = maxFontSize; } /** * Sets the max. phrase length.<p> * * @param maxPhraseLength the max. phrase length to set */ public void setMaxPhraseLength(int maxPhraseLength) { m_maxPhraseLength = maxPhraseLength; } /** * Sets the min. font size.<p> * * @param minFontSize the min. font size to set */ public void setMinFontSize(int minFontSize) { m_minFontSize = minFontSize; } /** * Sets the minimum phrase length.<p> * * @param minPhraseLength the minimum phrase length to set */ public void setMinPhraseLength(int minPhraseLength) { m_minPhraseLength = minPhraseLength; } /** * Returns the flag that decides whether a background image or a background color is used.<p> * * @param useBackgroundImage the flag that decides whether a background image or a background * color is used. */ public void setUseBackgroundImage(boolean useBackgroundImage) { m_useBackgroundImage = useBackgroundImage; } /** * Creates a request parameter string from including all captcha settings.<p> * * @param cms needed for the context / encoding * @return a request parameter string from including all captcha settings */ public String toRequestParams(CmsObject cms) { StringBuffer buf = new StringBuffer(2048); buf.append(C_PARAM_IMAGE_WIDTH).append(PARAM_KV_SEPARATOR).append(m_imageWidth); buf.append(PARAM_DELIM).append(C_PARAM_IMAGE_HEIGHT).append(PARAM_KV_SEPARATOR).append(m_imageHeight); buf.append(PARAM_DELIM).append(C_PARAM_MIN_FONT_SIZE).append(PARAM_KV_SEPARATOR).append(m_minFontSize); buf.append(PARAM_DELIM).append(C_PARAM_MAX_FONT_SIZE).append(PARAM_KV_SEPARATOR).append(m_maxFontSize); buf.append(PARAM_DELIM).append(C_PARAM_MIN_PHRASE_LENGTH).append(PARAM_KV_SEPARATOR).append(m_minPhraseLength); buf.append(PARAM_DELIM).append(C_PARAM_MAX_PHRASE_LENGTH).append(PARAM_KV_SEPARATOR).append(m_maxPhraseLength); buf.append(PARAM_DELIM).append(C_PARAM_FONT_COLOR).append(PARAM_KV_SEPARATOR).append( CmsEncoder.escape(getFontColorString(), cms.getRequestContext().getEncoding())); buf.append(PARAM_DELIM).append(C_PARAM_BACKGROUND_COLOR).append(PARAM_KV_SEPARATOR).append( CmsEncoder.escape(getBackgroundColorString(), cms.getRequestContext().getEncoding())); buf.append(PARAM_DELIM).append(C_PARAM_HOLES_PER_GLYPH).append(PARAM_KV_SEPARATOR).append(m_holesPerGlyph); buf.append(PARAM_DELIM).append(C_PARAM_FILTER_AMPLITUDE).append(PARAM_KV_SEPARATOR).append(m_filterAmplitude); buf.append(PARAM_DELIM).append(C_PARAM_FILTER_WAVE_LENGTH).append(PARAM_KV_SEPARATOR).append(m_filterWaveLength); if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(getCharacterPool())) { buf.append(PARAM_DELIM).append(C_PARAM_CHARACTERS).append(PARAM_KV_SEPARATOR).append(getCharacterPool()); } else { buf.append(PARAM_DELIM).append(C_PARAM_DICTIONARY).append(PARAM_KV_SEPARATOR).append(m_dictionary); } buf.append(PARAM_DELIM).append(C_PARAM_PRESET).append(PARAM_KV_SEPARATOR).append(m_presetPath); buf.append(PARAM_DELIM).append(C_PARAM_USE_BACKGROUND_IMAGE).append(PARAM_KV_SEPARATOR).append( Boolean.toString(m_useBackgroundImage)); String result = ""; // encrypt the parameters String encValues = encrypt(buf.toString()); if (encValues != null) { result = C_PARAM_DATA + PARAM_KV_SEPARATOR + encValues; } return result; } /** * @see java.lang.Object#clone() */ @Override protected Object clone() { CmsCaptchaSettings result = new CmsCaptchaSettings(); // copy all members here: result.m_backgroundColor = m_backgroundColor; result.m_filterAmplitude = m_filterAmplitude; result.m_filterWaveLength = m_filterWaveLength; result.m_fontColor = m_fontColor; result.m_holesPerGlyph = m_holesPerGlyph; result.m_imageHeight = m_imageHeight; result.m_imageWidth = m_imageWidth; result.m_maxFontSize = m_maxFontSize; result.m_maxPhraseLength = m_maxPhraseLength; result.m_minFontSize = m_minFontSize; result.m_useBackgroundImage = m_useBackgroundImage; result.m_minPhraseLength = m_minPhraseLength; result.m_characterPool = m_characterPool; result.m_presetPath = m_presetPath; result.m_dictionary = m_dictionary; result.m_mathField = m_mathField; return result; } /** * Returns the character Pool.<p> * * @return the character Pool */ String getCharacterPool() { if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(getDictionary())) { // dictionary has priority return ""; } if (CmsStringUtil.isEmptyOrWhitespaceOnly(m_characterPool)) { // default value return "abcdefghijklmnopqrstuvwxyz"; } return m_characterPool; } /** * Returns the preset path that was used to configure these settings.<p> * * This is read only, as the path is internally read from a nested CmsForm/FormCaptcha XML * content.<p> * * @return the preset path that was used to configure these settings */ String getPresetPath() { return m_presetPath; } /** * Sets the character Pool.<p> * * @param characterPool the character Pool to set */ void setCharacterPool(String characterPool) { m_characterPool = characterPool; } /** * Decrypts the given value which was encrypted with the encrypt method.<p> * * @param value the value to be decrypted * @return the decrypted string of the value or null if something went wrong */ private String decrypt(String value) { // check if given value is valid if (CmsStringUtil.isEmptyOrWhitespaceOnly(value)) { // no input available return null; } try { // create key Key key = new SecretKeySpec(getKey(), ENCRYPTION); Cipher cipher = Cipher.getInstance(ENCRYPTION); cipher.init(Cipher.DECRYPT_MODE, key); // decode from base64 byte[] cleartext = Base64.decodeBase64(value.getBytes()); // decrypt text byte[] ciphertext = cipher.doFinal(cleartext); return CmsEncoder.decode(new String(ciphertext)); } catch (Exception ex) { // error while decrypting } return null; } /** * Encrypts the given value.<p> * * @param value the string which should be encrypted * @return the encrypted string of the value or null if something went wrong */ private String encrypt(String value) { // check if given value is valid if (CmsStringUtil.isEmptyOrWhitespaceOnly(value)) { // no input available return null; } try { // create key byte[] k = getKey(); Key key = new SecretKeySpec(k, ENCRYPTION); Cipher cipher = Cipher.getInstance(ENCRYPTION); cipher.init(Cipher.ENCRYPT_MODE, key); // encrypt text byte[] cleartext = value.getBytes(FORMAT); byte[] ciphertext = cipher.doFinal(cleartext); // encode with base64 to be used as a url parameter return CmsEncoder.encode(new String(Base64.encodeBase64(ciphertext))); } catch (Exception ex) { // error while encrypting } return null; } /** * Converts the password to machine readable form.<p> * * @return the password in machine readable form */ private byte[] getKey() { try { MessageDigest md5 = MessageDigest.getInstance("MD5"); md5.update(PASSWORD.toString().getBytes()); byte[] key = md5.digest(); // now get the first 8 bytes byte[] finalKey = new byte[8]; for (int i = 0; i <= 7; i++) { finalKey[i] = key[i]; } return finalKey; } catch (NoSuchAlgorithmException ex) { // found no matching algorithm } return null; } /** * Returns the request parameter with the specified name.<p> * * @param parameter the parameter to return * * @return the parameter value */ private String getParameter(String parameter) { try { return (m_parameterMap.get(parameter))[0]; } catch (NullPointerException e) { return ""; } } /** * Converts a color range of a color into a hex string.<p> * * @param colorRange the color range of a color * @return the hex string of the color range */ private String toHexString(int colorRange) { if (colorRange < 10) { return "0" + Integer.toHexString(colorRange); } else { return Integer.toHexString(colorRange); } } }