1 /* 2 * 3 * Paros and its related class files. 4 * 5 * Paros is an HTTP/HTTPS proxy for assessing web application security. 6 * Copyright (C) 2003-2004 Chinotec Technologies Company 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the Clarified Artistic License 10 * as published by the Free Software Foundation. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * Clarified Artistic License for more details. 16 * 17 * You should have received a copy of the Clarified Artistic License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 20 */ 21 // ZAP: 2012/12/19 Code Cleanup: Moved array brackets from variable name to type 22 // ZAP: 2012/12/20 Added listener setter for persistentConnectionListenerList. 23 // ZAP: 2013/01/16 Issue 453: Dynamic loading and unloading of add-ons 24 // ZAP: 2013/04/14 Issue 608: Rename the method ExtensionHook.addSiteMapListner to 25 // addSiteMapListener 26 // ZAP: 2013/05/02 Re-arranged all modifiers into Java coding standard order 27 // ZAP: 2014/03/23 Issue 1022: Proxy - Allow to override a proxied message 28 // ZAP: 2014/10/25 Issue 1062: Added scannerhook to be added by extensions. 29 // ZAP: 2016/04/08 Allow to add ContextDataFactory 30 // ZAP: 2016/05/30 Allow to add AddOnInstallationStatusListener 31 // ZAP: 2016/05/30 Issue 2494: ZAP Proxy is not showing the HTTP CONNECT Request in history tab 32 // ZAP: 2016/08/18 Allow to add ApiImplementor 33 // ZAP: 2017/07/25 Allow to add HttpSenderListener. 34 // ZAP: 2017/11/23 Add an add method for OverrideMessageProxyListener. 35 // ZAP: 2019/06/01 Normalise line endings. 36 // ZAP: 2019/06/05 Normalise format/style. 37 // ZAP: 2020/08/27 Added support for plugable variants 38 package org.parosproxy.paros.extension; 39 40 import java.util.ArrayList; 41 import java.util.Collections; 42 import java.util.List; 43 import java.util.Vector; 44 import org.parosproxy.paros.common.AbstractParam; 45 import org.parosproxy.paros.core.proxy.ConnectRequestProxyListener; 46 import org.parosproxy.paros.core.proxy.OverrideMessageProxyListener; 47 import org.parosproxy.paros.core.proxy.ProxyListener; 48 import org.parosproxy.paros.core.scanner.ScannerHook; 49 import org.parosproxy.paros.core.scanner.Variant; 50 import org.parosproxy.paros.model.Model; 51 import org.zaproxy.zap.PersistentConnectionListener; 52 import org.zaproxy.zap.extension.AddOnInstallationStatusListener; 53 import org.zaproxy.zap.extension.AddonFilesChangedListener; 54 import org.zaproxy.zap.extension.api.ApiImplementor; 55 import org.zaproxy.zap.model.ContextDataFactory; 56 import org.zaproxy.zap.network.HttpSenderListener; 57 import org.zaproxy.zap.view.SiteMapListener; 58 59 public class ExtensionHook { 60 61 /** 62 * The hook for menus. 63 * 64 * <p>Lazily initialised. 65 * 66 * @see #getHookMenu() 67 * @see #getHookMenuNoInit() 68 */ 69 private ExtensionHookMenu hookMenu; 70 71 /** 72 * The hook for view components. 73 * 74 * <p>Lazily initialised. 75 * 76 * @see #getHookView() 77 * @see #getHookViewNoInit() 78 */ 79 private ExtensionHookView hookView; 80 81 private Model model = null; 82 private Vector<OptionsChangedListener> optionsListenerList = new Vector<>(); 83 84 private Vector<ProxyListener> proxyListenerList = new Vector<>(); 85 86 /** 87 * The {@link OverrideMessageProxyListener}s added to this extension hook. 88 * 89 * <p>Lazily initialised. 90 * 91 * @see #addOverrideMessageProxyListener(OverrideMessageProxyListener) 92 * @see #getOverrideMessageProxyListenerList() 93 */ 94 private List<OverrideMessageProxyListener> overrideMessageProxyListenersList; 95 96 /** 97 * The {@link ConnectRequestProxyListener}s added to this extension hook. 98 * 99 * <p>Lazily initialised. 100 * 101 * @see #addConnectionRequestProxyListener(ConnectRequestProxyListener) 102 * @see #getConnectRequestProxyListeners() 103 */ 104 private List<ConnectRequestProxyListener> connectRequestProxyListeners; 105 106 private Vector<SessionChangedListener> sessionListenerList = new Vector<>(); 107 private Vector<AbstractParam> optionsParamSetList = new Vector<>(); 108 // ZAP: Added support for site map listeners 109 private Vector<SiteMapListener> siteMapListenerList = new Vector<>(); 110 // ZAP: Added support for Scanner Hooks 111 private Vector<ScannerHook> scannerHookList = new Vector<>(); 112 private Vector<PersistentConnectionListener> persistentConnectionListenerList = new Vector<>(); 113 private List<AddonFilesChangedListener> addonFilesChangedListenerList = new ArrayList<>(); 114 115 /** 116 * The {@link ContextDataFactory}s added to this extension hook. 117 * 118 * <p>Lazily initialised. 119 * 120 * @see #addContextDataFactory(ContextDataFactory) 121 * @see #getContextDataFactories() 122 */ 123 private List<ContextDataFactory> contextDataFactories; 124 125 /** 126 * The {@link AddOnInstallationStatusListener}s added to this extension hook. 127 * 128 * <p>Lazily initialised. 129 * 130 * @see #addAddOnInstallationStatusListener(AddOnInstallationStatusListener) 131 * @see #getAddOnInstallationStatusListeners() 132 */ 133 private List<AddOnInstallationStatusListener> addOnInstallationStatusListeners; 134 135 /** 136 * The {@link ApiImplementor}s added to this extension hook. 137 * 138 * <p>Lazily initialised. 139 * 140 * @see #addApiImplementor(ApiImplementor) 141 * @see #getApiImplementors() 142 */ 143 private List<ApiImplementor> apiImplementors; 144 145 /** 146 * The {@link HttpSenderListener}s added to this extension hook. 147 * 148 * <p>Lazily initialised. 149 * 150 * @see #addHttpSenderListener(HttpSenderListener) 151 * @see #getHttpSenderListeners() 152 */ 153 private List<HttpSenderListener> httpSenderListeners; 154 155 /** 156 * The {@link Variant}s added to this extension hook. 157 * 158 * <p>Lazily initialised. 159 * 160 * @see #addVariant(Variant) 161 * @see #getVariants() 162 */ 163 private List<Class<? extends Variant>> variants; 164 165 private ViewDelegate view = null; 166 private CommandLineArgument[] arg = new CommandLineArgument[0]; 167 ExtensionHook(Model model, ViewDelegate view)168 public ExtensionHook(Model model, ViewDelegate view) { 169 this.view = view; 170 this.model = model; 171 } 172 addOptionsChangedListener(OptionsChangedListener listener)173 public void addOptionsChangedListener(OptionsChangedListener listener) { 174 optionsListenerList.add(listener); 175 } 176 addOptionsParamSet(AbstractParam paramSet)177 public void addOptionsParamSet(AbstractParam paramSet) { 178 optionsParamSetList.add(paramSet); 179 } 180 addProxyListener(ProxyListener listener)181 public void addProxyListener(ProxyListener listener) { 182 proxyListenerList.add(listener); 183 } 184 185 /** 186 * Adds the given {@link ConnectRequestProxyListener} to the extension hook, to be later 187 * notified of CONNECT requests received by the local proxy. 188 * 189 * <p>By default, the {@code ConnectRequestProxyListener}s added are removed from the local 190 * proxy when the extension is unloaded. 191 * 192 * @param listener the {@code ConnectRequestProxyListener} that will be added and then notified 193 * @throws IllegalArgumentException if the given {@code listener} is {@code null}. 194 * @since 2.5.0 195 */ addConnectionRequestProxyListener(ConnectRequestProxyListener listener)196 public void addConnectionRequestProxyListener(ConnectRequestProxyListener listener) { 197 if (listener == null) { 198 throw new IllegalArgumentException("Parameter listener must not be null."); 199 } 200 201 if (connectRequestProxyListeners == null) { 202 connectRequestProxyListeners = new ArrayList<>(); 203 } 204 connectRequestProxyListeners.add(listener); 205 } 206 207 /** 208 * Gets the {@link ConnectRequestProxyListener}s added to this hook. 209 * 210 * @return an unmodifiable {@code List} containing the added {@code 211 * ConnectRequestProxyListener}s, never {@code null}. 212 * @since 2.5.0 213 */ getConnectRequestProxyListeners()214 List<ConnectRequestProxyListener> getConnectRequestProxyListeners() { 215 if (connectRequestProxyListeners == null) { 216 return Collections.emptyList(); 217 } 218 return Collections.unmodifiableList(connectRequestProxyListeners); 219 } 220 addSessionListener(SessionChangedListener listener)221 public void addSessionListener(SessionChangedListener listener) { 222 sessionListenerList.add(listener); 223 } 224 225 /** 226 * @deprecated Replaced by the method {@link #addSiteMapListener(SiteMapListener)}. It will be 227 * removed in a future release. 228 */ 229 @Deprecated addSiteMapListner(SiteMapListener listener)230 public void addSiteMapListner(SiteMapListener listener) { 231 siteMapListenerList.add(listener); 232 } 233 addSiteMapListener(SiteMapListener listener)234 public void addSiteMapListener(SiteMapListener listener) { 235 siteMapListenerList.add(listener); 236 } 237 238 // ZAP: add a scanner hook addScannerHook(ScannerHook hook)239 public void addScannerHook(ScannerHook hook) { 240 scannerHookList.add(hook); 241 } 242 addPersistentConnectionListener(PersistentConnectionListener listener)243 public void addPersistentConnectionListener(PersistentConnectionListener listener) { 244 persistentConnectionListenerList.add(listener); 245 } 246 addCommandLine(CommandLineArgument[] arg)247 public void addCommandLine(CommandLineArgument[] arg) { 248 this.arg = arg; 249 } 250 addAddonFilesChangedListener(AddonFilesChangedListener listener)251 public void addAddonFilesChangedListener(AddonFilesChangedListener listener) { 252 addonFilesChangedListenerList.add(listener); 253 } 254 255 /** 256 * Adds the given {@code listener} to the extension hook, to be later notified of changes in the 257 * installation status of the add-ons. 258 * 259 * @param listener the listener that will be added and then notified 260 * @throws IllegalArgumentException if the given {@code listener} is {@code null}. 261 * @since 2.5.0 262 */ addAddOnInstallationStatusListener(AddOnInstallationStatusListener listener)263 public void addAddOnInstallationStatusListener(AddOnInstallationStatusListener listener) { 264 if (listener == null) { 265 throw new IllegalArgumentException("Parameter listener must not be null."); 266 } 267 268 if (addOnInstallationStatusListeners == null) { 269 addOnInstallationStatusListeners = new ArrayList<>(); 270 } 271 addOnInstallationStatusListeners.add(listener); 272 } 273 274 /** 275 * Gets the {@link AddOnInstallationStatusListener}s added to this hook. 276 * 277 * @return an unmodifiable {@code List} containing the added {@code 278 * AddOnInstallationStatusListener}s, never {@code null}. 279 * @since 2.5.0 280 */ getAddOnInstallationStatusListeners()281 List<AddOnInstallationStatusListener> getAddOnInstallationStatusListeners() { 282 if (addOnInstallationStatusListeners == null) { 283 return Collections.emptyList(); 284 } 285 return Collections.unmodifiableList(addOnInstallationStatusListeners); 286 } 287 288 /** 289 * Gets the hook for menus. 290 * 291 * @return the hook for menus, never {@code null}. 292 */ getHookMenu()293 public ExtensionHookMenu getHookMenu() { 294 if (hookMenu == null) { 295 hookMenu = new ExtensionHookMenu(); 296 } 297 return hookMenu; 298 } 299 300 /** 301 * Gets the hook for menus, without initialising it. 302 * 303 * @return the hook for menus, might be {@code null}. 304 * @since 2.8.0 305 */ getHookMenuNoInit()306 ExtensionHookMenu getHookMenuNoInit() { 307 return hookMenu; 308 } 309 310 /** 311 * Gets the hook for view components. 312 * 313 * @return the hook for view components, never {@code null}. 314 */ getHookView()315 public ExtensionHookView getHookView() { 316 if (hookView == null) { 317 hookView = new ExtensionHookView(); 318 } 319 return hookView; 320 } 321 322 /** 323 * Gets the hook for view components, without initialising it. 324 * 325 * @return the hook for view components, might be {@code null}. 326 * @since 2.8.0 327 */ getHookViewNoInit()328 ExtensionHookView getHookViewNoInit() { 329 return hookView; 330 } 331 332 /** @return Returns the model. */ getModel()333 public Model getModel() { 334 return model; 335 } 336 337 /** @return Returns the optionsListenerList. */ getOptionsChangedListenerList()338 public Vector<OptionsChangedListener> getOptionsChangedListenerList() { 339 return optionsListenerList; 340 } 341 getOptionsParamSetList()342 public Vector<AbstractParam> getOptionsParamSetList() { 343 return optionsParamSetList; 344 } 345 346 /** @return Returns the proxyListenerList. */ getProxyListenerList()347 public Vector<ProxyListener> getProxyListenerList() { 348 return proxyListenerList; 349 } 350 351 /** @return Returns the sessionListenerList. */ getSessionListenerList()352 public Vector<SessionChangedListener> getSessionListenerList() { 353 return sessionListenerList; 354 } 355 getSiteMapListenerList()356 public Vector<SiteMapListener> getSiteMapListenerList() { 357 return siteMapListenerList; 358 } 359 360 // ZAP: get all scannerhooks (used by extensionloader and the scanner) getScannerHookList()361 public Vector<ScannerHook> getScannerHookList() { 362 return scannerHookList; 363 } 364 getPersistentConnectionListener()365 public Vector<PersistentConnectionListener> getPersistentConnectionListener() { 366 return persistentConnectionListenerList; 367 } 368 369 /** @return Returns the view. */ getView()370 public ViewDelegate getView() { 371 return view; 372 } 373 getCommandLineArgument()374 public CommandLineArgument[] getCommandLineArgument() { 375 return arg; 376 } 377 getAddonFilesChangedListener()378 public List<AddonFilesChangedListener> getAddonFilesChangedListener() { 379 return addonFilesChangedListenerList; 380 } 381 382 /** 383 * Adds the given {@code overrideMessageProxyListener} to the extension hook, to be later added 384 * to the {@link org.parosproxy.paros.control.Proxy Proxy}. 385 * 386 * <p>By default, the {@code OverrideMessageProxyListener}s added to this extension hook are 387 * removed from the {@code Proxy} when the extension is unloaded. 388 * 389 * @param overrideMessageProxyListener the {@code OverrideMessageProxyListener} that will be 390 * added to the {@code Proxy} 391 * @throws IllegalArgumentException if the given {@code overrideMessageProxyListener} is {@code 392 * null}. 393 * @since 2.7.0 394 */ addOverrideMessageProxyListener( OverrideMessageProxyListener overrideMessageProxyListener)395 public void addOverrideMessageProxyListener( 396 OverrideMessageProxyListener overrideMessageProxyListener) { 397 getOverrideMessageProxyListenerList().add(overrideMessageProxyListener); 398 } 399 400 /** 401 * Gets the {@link OverrideMessageProxyListener}s added to this hook. 402 * 403 * <p>While it's possible to add the listener with this method it's not recommended, use {@link 404 * #addOverrideMessageProxyListener(OverrideMessageProxyListener)} whenever possible. The 405 * accessibility of this method might change in a future version (to package access). 406 * 407 * @return a {@code List} containing the added {@code OverrideMessageProxyListener}s, never 408 * {@code null}. 409 * @since 2.3.0 410 */ getOverrideMessageProxyListenerList()411 public List<OverrideMessageProxyListener> getOverrideMessageProxyListenerList() { 412 if (overrideMessageProxyListenersList == null) { 413 overrideMessageProxyListenersList = new ArrayList<>(); 414 } 415 return overrideMessageProxyListenersList; 416 } 417 418 /** 419 * Adds the given {@link ContextDataFactory} to the extension hook, to be later added to the 420 * {@link Model}. 421 * 422 * <p>By default, the {@code ContextDataFactory}s added are removed from the {@code Model} when 423 * the extension is unloaded. 424 * 425 * @param contextDataFactory the {@code ContextDataFactory} that will be added to the {@code 426 * Model} 427 * @since 2.5.0 428 */ addContextDataFactory(ContextDataFactory contextDataFactory)429 public void addContextDataFactory(ContextDataFactory contextDataFactory) { 430 if (contextDataFactories == null) { 431 contextDataFactories = new ArrayList<>(); 432 } 433 contextDataFactories.add(contextDataFactory); 434 } 435 436 /** 437 * Gets the {@link ContextDataFactory}s added to this hook. 438 * 439 * @return an unmodifiable {@code List} containing the added {@code ContextDataFactory}s, never 440 * {@code null}. 441 * @since 2.5.0 442 */ getContextDataFactories()443 List<ContextDataFactory> getContextDataFactories() { 444 if (contextDataFactories == null) { 445 return Collections.emptyList(); 446 } 447 return Collections.unmodifiableList(contextDataFactories); 448 } 449 450 /** 451 * Adds the given {@code apiImplementor} to the extension hook, to be later added to the {@link 452 * org.zaproxy.zap.extension.api.API API}. 453 * 454 * <p>By default, the {@code ApiImplementor}s added to this extension hook are removed from the 455 * {@code API} when the extension is unloaded. 456 * 457 * @param apiImplementor the ApiImplementor that will be added to the ZAP API 458 * @throws IllegalArgumentException if the given {@code apiImplementor} is {@code null}. 459 * @since 2.6.0 460 */ addApiImplementor(ApiImplementor apiImplementor)461 public void addApiImplementor(ApiImplementor apiImplementor) { 462 if (apiImplementor == null) { 463 throw new IllegalArgumentException("Parameter apiImplementor must not be null."); 464 } 465 466 if (apiImplementors == null) { 467 apiImplementors = new ArrayList<>(); 468 } 469 apiImplementors.add(apiImplementor); 470 } 471 472 /** 473 * Gets the {@link ApiImplementor}s added to this hook. 474 * 475 * @return an unmodifiable {@code List} containing the added {@code ApiImplementor}s, never 476 * {@code null}. 477 * @since 2.6.0 478 */ getApiImplementors()479 List<ApiImplementor> getApiImplementors() { 480 if (apiImplementors == null) { 481 return Collections.emptyList(); 482 } 483 return Collections.unmodifiableList(apiImplementors); 484 } 485 486 /** 487 * Adds the given {@code httpSenderListener} to the extension hook, to be later added to the 488 * {@link org.parosproxy.paros.network.HttpSender HttpSender}. 489 * 490 * <p>By default, the {@code HttpSenderListener}s added to this extension hook are removed from 491 * the {@code HttpSender} when the extension is unloaded. 492 * 493 * @param httpSenderListener the HttpSenderListener that will be added to the {@code HttpSender} 494 * @throws IllegalArgumentException if the given {@code httpSenderListener} is {@code null}. 495 * @since 2.7.0 496 */ addHttpSenderListener(HttpSenderListener httpSenderListener)497 public void addHttpSenderListener(HttpSenderListener httpSenderListener) { 498 if (httpSenderListener == null) { 499 throw new IllegalArgumentException("Parameter httpSenderListener must not be null."); 500 } 501 502 if (httpSenderListeners == null) { 503 httpSenderListeners = new ArrayList<>(); 504 } 505 httpSenderListeners.add(httpSenderListener); 506 } 507 508 /** 509 * Gets the {@link HttpSenderListener}s added to this hook. 510 * 511 * @return an unmodifiable {@code List} containing the added {@code HttpSenderListener}s, never 512 * {@code null}. 513 * @since 2.7.0 514 */ getHttpSenderListeners()515 List<HttpSenderListener> getHttpSenderListeners() { 516 if (httpSenderListeners == null) { 517 return Collections.emptyList(); 518 } 519 return Collections.unmodifiableList(httpSenderListeners); 520 } 521 522 /** 523 * Adds the given {@code variant} to the extension hook, to be later added to the {@link 524 * org.parosproxy.paros.model.Model Model}. 525 * 526 * <p>By default, the {@code Variant}s added to this extension hook are removed from the {@code 527 * Model} when the extension is unloaded. 528 * 529 * @param variant the Variant that will be added to the {@code Model} 530 * @throws IllegalArgumentException if the given {@code variant} is {@code null}. 531 * @since 2.10.0 532 */ addVariant(Class<? extends Variant> variant)533 public void addVariant(Class<? extends Variant> variant) { 534 if (variant == null) { 535 throw new IllegalArgumentException("Parameter variant must not be null."); 536 } 537 538 if (variants == null) { 539 variants = new ArrayList<>(); 540 } 541 variants.add(variant); 542 } 543 544 /** 545 * Gets the {@link Variant}s added to this hook. 546 * 547 * @return an unmodifiable {@code List} containing the added {@code Variant}s, never {@code 548 * null}. 549 * @since 2.10.0 550 */ getVariants()551 List<Class<? extends Variant>> getVariants() { 552 if (variants == null) { 553 return Collections.emptyList(); 554 } 555 return Collections.unmodifiableList(variants); 556 } 557 } 558