Commit ec7aa130 authored by Gaston Dombiak's avatar Gaston Dombiak Committed by gato

git-svn-id: http://svn.igniterealtime.org/svn/repos/messenger/trunk@3201 b35dd754-fafc-0310-a699-88a17e54d16e
parent c7bfaedc
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.messenger.plugin;
import org.xmpp.packet.Message;
import java.util.ArrayList;
import java.util.Collection;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Filters message content using regular expressions. If a content mask is
* provided message content will be altered.
*
* @author Conor Hayes
*/
public class ContentFilter {
private String patterns;
private Collection<Pattern> compiledPatterns = new ArrayList<Pattern>();
private String mask;
/**
* A default instance will allow all message content.
*
* @see #setPatterns(String)
* @see #setMask(String)
*/
public ContentFilter() {
}
/**
* Set the patterns to use for searching content.
*
* @param regExps a comma separated String of regular expressions
*/
public void setPatterns(String patterns) {
if (patterns != null) {
this.patterns = patterns;
String[] data = patterns.split(",");
compiledPatterns.clear();
for (int i = 0; i < data.length; i++) {
compiledPatterns.add(Pattern.compile(data[i]));
}
}
else {
clearPatterns();
}
}
public String getPatterns() {
return this.patterns;
}
/**
* Clears all patterns. Calling this method means that all message content
* will be allowed.
*/
public void clearPatterns() {
patterns = null;
compiledPatterns.clear();
}
/**
* Set the content replacement mask.
*
* @param mask the mask to use when replacing content
*/
public void setMask(String mask) {
this.mask = mask;
}
/**
* @return the current mask or null if none has been set
*/
public String getMask() {
return mask;
}
/**
* Clears the content mask.
*
* @see #filter(Message)
*/
public void clearMask() {
mask = null;
}
/**
* @return true if the filter is currently masking content, false otherwise
*/
public boolean isMaskingContent() {
return mask != null;
}
/**
* Filters message content.
*
* @param msg the message to filter, its subject/body may be altered if there
* are content matches and a content mask is set
* @return true if the msg content matched up, false otherwise
*/
public boolean filter(Message msg) {
boolean hasMatch = false;
if (msg.getSubject() != null) {
if (hasMatch(msg.getSubject())) {
hasMatch = true;
if (isMaskingContent()) {
String newSubject = replaceContent(msg.getSubject());
msg.setSubject(newSubject);
}
}
}
if (msg.getBody() != null) {
if (hasMatch(msg.getBody())) {
hasMatch = true;
if (isMaskingContent()) {
String newBody = replaceContent(msg.getBody());
msg.setBody(newBody);
}
}
}
return hasMatch;
}
private String replaceContent(String content) {
for (Pattern pattern : compiledPatterns) {
Matcher m = pattern.matcher(content);
content = m.replaceAll(mask);
}
return content;
}
/**
* Performs sequential search for any pattern match.
*
* @param content the content to search against
* @return true if a match is found, false otherwise
*/
private boolean hasMatch(String content) {
boolean hasMatch = false;
for (Pattern pattern : compiledPatterns) {
Matcher m = pattern.matcher(content);
if (m.find()) {
hasMatch = true;
break;
}
}
return hasMatch;
}
}
\ No newline at end of file
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.messenger.plugin;
import org.jivesoftware.messenger.MessageRouter;
import org.jivesoftware.messenger.Session;
import org.jivesoftware.messenger.XMPPServer;
import org.jivesoftware.messenger.container.Plugin;
import org.jivesoftware.messenger.container.PluginManager;
import org.jivesoftware.messenger.interceptor.InterceptorManager;
import org.jivesoftware.messenger.interceptor.PacketInterceptor;
import org.jivesoftware.messenger.interceptor.PacketRejectedException;
import org.jivesoftware.util.JiveGlobals;
import org.xmpp.packet.JID;
import org.xmpp.packet.Message;
import org.xmpp.packet.Packet;
import java.io.File;
/**
* Content filter plugin.
*
* @author Conor Hayes
*/
public class ContentFilterPlugin implements Plugin, PacketInterceptor {
/**
* The expected value is a boolean, if true the user identified by the value
* of the property #VIOLATION_NOTIFICATION_CONTACT_PROPERTY will be notified
* every time there is a content match, otherwise no notification will be
* sent. Then default value is false.
*/
public static final String VIOLATION_NOTIFICATION_ENABLED_PROPERTY =
"plugin.contentFilter.violation.notification.enabled";
/**
* The expected value is a user name. The default value is "admin".
*/
public static final String VIOLATION_NOTIFICATION_CONTACT_PROPERTY =
"plugin.contentFilter.violation.notification.contact";
/**
* The expected value is a boolean, if true the sender will be notified when a
* message is rejected, otherwise the message will be silently rejected,i.e. the
* sender will not know that the message was rejected and the receiver will
* not get the message. The default value is false.
*/
public static final String REJECTION_NOTIFICATION_ENABLED_PROPERTY =
"plugin.contentFilter.rejection.notification.enabled";
/**
* The expected value is a string, containing the desired message for the
* sender notification.
*/
public static final String REJECTION_MSG_PROPERTY = "plugin.contentFilter.rejection.msg";
/**
* The expected value is a boolean, if true the value of #PATTERNS_PROPERTY
* will be used for pattern matching.
*/
public static final String PATTERNS_ENABLED_PROPERTY = "plugin.contentFilter.patterns.enabled";
/**
* The expected value is a comma separated string of regular expressions.
*/
public static final String PATTERNS_PROPERTY = "plugin.contentFilter.patterns";
/**
* The expected value is a boolean, if true the value of #MASK_PROPERTY will
* be used to mask matching content.
*/
public static final String MASK_ENABLED_PROPERTY = "plugin.contentFilter.mask.enabled";
/**
* The expected value is a string. If this property is set any
* matching content will not be rejected but masked with the given value.
* Setting a content mask means that property #SENDER_NOTIFICATION_ENABLED_PROPERTY
* is ignored. The default value is "**".
*/
public static final String MASK_PROPERTY = "plugin.contentFilter.mask";
/**
* the hook into the inteceptor chain
*/
private InterceptorManager interceptorManager;
/**
* used to send violation notifications
*/
private MessageRouter messageRouter;
/**
* delegate that does the real work of this plugin
*/
private ContentFilter contentFilter;
/**
* flags if sender should be notified of rejections
*/
private boolean rejectionNotificationEnabled;
/**
* the rejection msg to send
*/
private String rejectionMessage;
/**
* flags if content matches should result in admin notification
*/
private boolean violationNotificationEnabled;
/**
* the admin user to send violation notifications to
*/
private String violationContact;
/**
* flag if patterns should be used
*/
private boolean patternsEnabled;
/**
* the patterns to use
*/
private String patterns;
/**
* flag if mask should be used
*/
private boolean maskEnabled;
/**
* the mask to use
*/
private String mask;
/**
* violation notification messages will be from this JID
*/
private JID violationNotificationFrom;
public ContentFilterPlugin() {
contentFilter = new ContentFilter();
interceptorManager = InterceptorManager.getInstance();
violationNotificationFrom = new JID(XMPPServer.getInstance()
.getServerInfo().getName());
messageRouter = XMPPServer.getInstance().getMessageRouter();
}
public boolean isMaskEnabled() {
return maskEnabled;
}
public void setMaskEnabled(boolean enabled) {
maskEnabled = enabled;
JiveGlobals.setProperty(MASK_ENABLED_PROPERTY, enabled ? "true" : "false");
changeContentFilterMask();
}
public void setMask(String mas) {
mask = mas;
JiveGlobals.setProperty(MASK_PROPERTY, mas);
changeContentFilterMask();
}
private void changeContentFilterMask() {
if (maskEnabled) {
contentFilter.setMask(mask);
}
else {
contentFilter.clearMask();
}
}
public String getMask() {
return mask;
}
public boolean isPatternsEnabled() {
return patternsEnabled;
}
public void setPatternsEnabled(boolean enabled) {
patternsEnabled = enabled;
JiveGlobals.setProperty(PATTERNS_ENABLED_PROPERTY, enabled ? "true"
: "false");
changeContentFilterPatterns();
}
public void setPatterns(String patt) {
patterns = patt;
JiveGlobals.setProperty(PATTERNS_PROPERTY, patt);
changeContentFilterPatterns();
}
private void changeContentFilterPatterns() {
if (patternsEnabled) {
contentFilter.setPatterns(patterns);
}
else {
contentFilter.clearPatterns();
}
}
public String getPatterns() {
return patterns;
}
public boolean isRejectionNotificationEnabled() {
return rejectionNotificationEnabled;
}
public void setRejectionNotificationEnabled(boolean enabled) {
rejectionNotificationEnabled = enabled;
JiveGlobals.setProperty(REJECTION_NOTIFICATION_ENABLED_PROPERTY,
enabled ? "true" : "false");
}
public String getRejectionMessage() {
return rejectionMessage;
}
public void setRejectionMessage(String message) {
this.rejectionMessage = message;
JiveGlobals.setProperty(REJECTION_MSG_PROPERTY, message);
}
public boolean isViolationNotificationEnabled() {
return violationNotificationEnabled;
}
public void setViolationNotificationEnabled(boolean enabled) {
violationNotificationEnabled = enabled;
JiveGlobals.setProperty(VIOLATION_NOTIFICATION_ENABLED_PROPERTY,
enabled ? "true" : "false");
}
public void setViolationContact(String contact) {
violationContact = contact;
JiveGlobals.setProperty(VIOLATION_NOTIFICATION_CONTACT_PROPERTY, contact);
}
public String getViolationContact() {
return violationContact;
}
public void initializePlugin(PluginManager pManager, File pluginDirectory) {
// configure this plugin
initFilter();
// register with interceptor manager
interceptorManager.addInterceptor(this);
}
private void initFilter() {
// default to false
violationNotificationEnabled = JiveGlobals.getBooleanProperty(
VIOLATION_NOTIFICATION_ENABLED_PROPERTY, false);
// default to "admin"
violationContact = JiveGlobals.getProperty(VIOLATION_NOTIFICATION_CONTACT_PROPERTY,
"admin");
// default to false
rejectionNotificationEnabled = JiveGlobals.getBooleanProperty(
REJECTION_NOTIFICATION_ENABLED_PROPERTY, false);
// default to english
rejectionMessage = JiveGlobals.getProperty(REJECTION_MSG_PROPERTY,
"Message rejected. This is an automated server response");
// default to false
patternsEnabled = JiveGlobals.getBooleanProperty(PATTERNS_ENABLED_PROPERTY,
false);
//default to "fox,dog"
patterns = JiveGlobals.getProperty(PATTERNS_PROPERTY, "fox,dog");
changeContentFilterPatterns();
// default to false
maskEnabled = JiveGlobals.getBooleanProperty(MASK_ENABLED_PROPERTY, false);
//default to "***"
mask = JiveGlobals.getProperty(MASK_PROPERTY, "***");
changeContentFilterMask();
}
/**
* @see org.jivesoftware.messenger.container.Plugin#destroyPlugin()
*/
public void destroyPlugin() {
// unregister with interceptor manager
interceptorManager.removeInterceptor(this);
}
public void interceptPacket(Packet packet, Session session, boolean read,
boolean processed) throws PacketRejectedException {
if (patternsEnabled && !processed && (packet instanceof Message)) {
Message msg = (Message) packet;
// filter the message
boolean contentMatched = contentFilter.filter(msg);
// notify contact of violations
if (contentMatched && violationNotificationEnabled) {
sendViolationNotification(msg);
}
// reject the message if not masking content
if (contentMatched && !maskEnabled) {
PacketRejectedException rejected = new PacketRejectedException(
"Message rejected with disallowed content!");
if (rejectionNotificationEnabled) {
// let the sender know about the rejection, this is
// only possible/useful if the content is not masked
rejected.setRejectionMessage(rejectionMessage);
}
throw rejected;
}
}
}
private void sendViolationNotification(Message offendingMsg) {
String subject = "Content filter notification!";
String msg = "Disallowed content detected in message from:"
+ offendingMsg.getFrom() + " to:" + offendingMsg.getTo()
+ ", message was "
+ (contentFilter.isMaskingContent() ? "altered" : "rejected");
messageRouter.route(createServerMessage(subject, msg));
}
private Message createServerMessage(String subject, String body) {
Message message = new Message();
message.setTo(violationContact + "@"
+ violationNotificationFrom.getDomain());
message.setFrom(violationNotificationFrom);
message.setSubject(subject);
message.setBody(body);
return message;
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment