001/* 002 Licensed to the Apache Software Foundation (ASF) under one 003 or more contributor license agreements. See the NOTICE file 004 distributed with this work for additional information 005 regarding copyright ownership. The ASF licenses this file 006 to you under the Apache License, Version 2.0 (the 007 "License"); you may not use this file except in compliance 008 with the License. You may obtain a copy of the License at 009 010 http://www.apache.org/licenses/LICENSE-2.0 011 012 Unless required by applicable law or agreed to in writing, 013 software distributed under the License is distributed on an 014 "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 KIND, either express or implied. See the License for the 016 specific language governing permissions and limitations 017 under the License. 018 */ 019package org.apache.wiki.plugin; 020 021import org.apache.wiki.api.core.Attachment; 022import org.apache.wiki.api.core.Context; 023import org.apache.wiki.api.core.ContextEnum; 024import org.apache.wiki.api.core.Engine; 025import org.apache.wiki.api.exceptions.PluginException; 026import org.apache.wiki.api.exceptions.ProviderException; 027import org.apache.wiki.api.plugin.Plugin; 028import org.apache.wiki.attachment.AttachmentManager; 029import org.apache.wiki.parser.MarkupParser; 030import org.apache.wiki.util.TextUtil; 031 032import java.util.Map; 033 034 035/** 036 * Provides an image plugin for better control than is possible with a simple image inclusion. 037 * <br> Most parameters are equivalents of the html image attributes. 038 * 039 * <p>Parameters : </p> 040 * <ul> 041 * <li><b>src</b> - the source (a URL) of the image (required parameter)</li> 042 * <li><b>align</b> - the alignment of the image</li> 043 * <li><b>height</b> - the height of the image</li> 044 * <li><b>width</b> - the width of the image</li> 045 * <li><b>alt</b> - alternate text</li> 046 * <li><b>caption</b> - the caption for the image</li> 047 * <li><b>link</b> - the hyperlink for the image</li> 048 * <li><b>target</b> - the target (frame) to be used for opening the image</li> 049 * <li><b>style</b> - the style attribute of the image</li> 050 * <li><b>class</b> - the associated class for the image</li> 051 * <li><b>border</b> - the border for the image</li> 052 * <li><b>title</b> - the title for the image, can be presented as a tooltip to the user</li> 053 * </ul> 054 * 055 * @since 2.1.4. 056 */ 057// FIXME: It is not yet possible to do wiki internal links. In order to do this cleanly, a TranslatorReader revamp is needed. 058public class Image implements Plugin { 059 060 /** The parameter name for setting the src. Value is <tt>{@value}</tt>. */ 061 public static final String PARAM_SRC = "src"; 062 /** The parameter name for setting the align parameter. Value is <tt>{@value}</tt>. */ 063 public static final String PARAM_ALIGN = "align"; 064 /** The parameter name for setting the height. Value is <tt>{@value}</tt>. */ 065 public static final String PARAM_HEIGHT = "height"; 066 /** The parameter name for setting the width. Value is <tt>{@value}</tt>. */ 067 public static final String PARAM_WIDTH = "width"; 068 /** The parameter name for setting the alt. Value is <tt>{@value}</tt>. */ 069 public static final String PARAM_ALT = "alt"; 070 /** The parameter name for setting the caption. Value is <tt>{@value}</tt>. */ 071 public static final String PARAM_CAPTION = "caption"; 072 /** The parameter name for setting the link. Value is <tt>{@value}</tt>. */ 073 public static final String PARAM_LINK = "link"; 074 /** The parameter name for setting the target. Value is <tt>{@value}</tt>. */ 075 public static final String PARAM_TARGET = "target"; 076 /** The parameter name for setting the style. Value is <tt>{@value}</tt>. */ 077 public static final String PARAM_STYLE = "style"; 078 /** The parameter name for setting the class. Value is <tt>{@value}</tt>. */ 079 public static final String PARAM_CLASS = "class"; 080 /** The parameter name for setting the border. Value is <tt>{@value}</tt>. */ 081 public static final String PARAM_BORDER = "border"; 082 /** The parameter name for setting the title. Value is <tt>{@value}</tt>. */ 083 public static final String PARAM_TITLE = "title"; 084 085 /** 086 * This method is used to clean away things like quotation marks which 087 * a malicious user could use to stop processing and insert javascript. 088 */ 089 private static String getCleanParameter( final Map< String, String > params, final String paramId ) { 090 return TextUtil.replaceEntities( params.get( paramId ) ); 091 } 092 private boolean needsSanitization(String link) { 093 String testVal = link.toLowerCase().replaceAll("\\s+", "").trim(); 094 if (testVal.startsWith("data") 095 || testVal.startsWith("javascript") 096 || testVal.startsWith("vbscript")) { 097 return true; 098 } 099 return false; 100 } 101 /** 102 * {@inheritDoc} 103 */ 104 @Override 105 public String execute( final Context context, final Map<String, String> params ) throws PluginException { 106 final Engine engine = context.getEngine(); 107 String src = getCleanParameter( params, PARAM_SRC ); 108 final String align = getCleanParameter( params, PARAM_ALIGN ); 109 final String ht = getCleanParameter( params, PARAM_HEIGHT ); 110 final String wt = getCleanParameter( params, PARAM_WIDTH ); 111 final String alt = getCleanParameter( params, PARAM_ALT ); 112 final String caption = getCleanParameter( params, PARAM_CAPTION ); 113 String link = getCleanParameter( params, PARAM_LINK ); 114 String target = getCleanParameter( params, PARAM_TARGET ); 115 final String style = getCleanParameter( params, PARAM_STYLE ); 116 final String cssclass= getCleanParameter( params, PARAM_CLASS ); 117 final String border = getCleanParameter( params, PARAM_BORDER ); 118 final String title = getCleanParameter( params, PARAM_TITLE ); 119 120 if( src == null ) { 121 throw new PluginException("Parameter 'src' is required for Image plugin"); 122 } 123 124 //if( cssclass == null ) cssclass = "imageplugin"; 125 126 if( target != null && !validTargetValue(target) ) { 127 target = null; // not a valid value so ignore 128 } 129 130 try { 131 final AttachmentManager mgr = engine.getManager( AttachmentManager.class ); 132 final Attachment att = mgr.getAttachmentInfo( context, src ); 133 134 if( att != null ) { 135 src = context.getURL( ContextEnum.PAGE_ATTACH.getRequestContext(), att.getName() ); 136 } 137 } catch( final ProviderException e ) { 138 throw new PluginException( "Attachment info failed: " + e.getMessage() ); 139 } 140 141 final StringBuilder result = new StringBuilder(); 142 143 result.append( "<table border=\"0\" class=\"imageplugin\"" ); 144 145 if( title != null ) { 146 result.append( " title=\"" ).append( title ).append( "\"" ); 147 } 148 149 if( align != null ) { 150 if( align.equals( "center" ) ) { 151 result.append( " style=\"margin-left: auto; margin-right: auto; text-align:center; vertical-align:middle;\"" ); 152 } else { 153 result.append( " style=\"float:" ).append( align ).append( ";\"" ); 154 } 155 } 156 157 result.append( ">\n" ); 158 159 if( caption != null ) { 160 result.append( "<caption>" ).append( caption ).append( "</caption>\n" ); 161 } 162 163 // move css class and style to the container of the image, so it doesn't affect the caption 164 result.append( "<tr><td" ); 165 166 if( cssclass != null ) { 167 result.append( " class=\"" ).append( cssclass ).append( "\"" ); 168 } 169 170 if( style != null ) { 171 result.append( " style=\"" ).append( style ); 172 173 // Make sure that we add a ";" to the end of the style string 174 if( result.charAt( result.length()-1 ) != ';' ) { 175 result.append( ";" ); 176 } 177 178 result.append("\""); 179 } 180 181 result.append( ">" ); 182 183 if( link != null ) { 184 if( !context.getBooleanWikiProperty( MarkupParser.PROP_ALLOWHTML, false ) ) { 185 if (needsSanitization(link)) { 186 link = "http://invalid_url" + link; 187 } 188 } 189 result.append( "<a href=\"" ).append( link ).append( "\"" ); 190 if( target != null ) { 191 result.append( " target=\"" ).append( target ).append( "\"" ); 192 } 193 result.append(">"); 194 } 195 196 if(!context.getBooleanWikiProperty(MarkupParser.PROP_ALLOWHTML, false)) { 197 if (needsSanitization(src)) { 198 src = "http://invalid_url" + src; 199 } 200 } 201 result.append( "<img src=\"" ).append( src ).append( "\"" ); 202 203 if( ht != null ) { 204 result.append( " height=\"" ).append( ht ).append( "\"" ); 205 } 206 if( wt != null ) { 207 result.append( " width=\"" ).append( wt ).append( "\"" ); 208 } 209 if( alt != null ) { 210 result.append( " alt=\"" ).append( alt ).append( "\"" ); 211 } 212 if( border != null ) { 213 result.append( " border=\"" ).append( border ).append( "\"" ); 214 } 215 // if( map != null ) result.append(" map=\""+map+"\""); 216 217 result.append(" />"); 218 if( link != null ) { 219 result.append("</a>"); 220 } 221 result.append("</td></tr>\n"); 222 result.append("</table>\n"); 223 224 return result.toString(); 225 } 226 227 private boolean validTargetValue( final String s ) { 228 if( s.equals("_blank") 229 || s.equals("_self") 230 || s.equals("_parent") 231 || s.equals("_top") ) { 232 return true; 233 } else if( !s.isEmpty() ) { // check [a-zA-z] 234 final char c = s.charAt(0); 235 return Character.isLowerCase(c) || Character.isUpperCase(c); 236 } 237 return false; 238 } 239 240}