view src/nabble/view/web/tools/SpamRules.java @ 0:7ecd1a4ef557

add content
author Franklin Schmidt <fschmidt@gmail.com>
date Thu, 21 Mar 2019 19:15:52 -0600
parents
children
line wrap: on
line source


package nabble.view.web.tools;

import nabble.model.DailyNumber;
import nabble.model.ModelException;
import nabble.model.Person;
import nabble.model.SystemProperties;
import nabble.model.User;
import nabble.view.lib.Jtp;
import nabble.view.lib.Shared;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;


public final class SpamRules extends HttpServlet {

	private static final Logger logger = LoggerFactory.getLogger(SpamRules.class);

	private static final List<Rule> RULES = new ArrayList<Rule>();

	static {
		String spamRules = SystemProperties.get("spam.rules");
		if (spamRules != null)
			RULES.addAll(parseRules(spamRules));
	}

	private interface Rule {
		public String checkSubject(String subject) throws ModelException.SpamException;
		public String checkMessage(String message, Person visitor) throws ModelException.SpamException;
	}
/*
	public static void checkSubject(HttpServletRequest request, String subject)
		throws ModelException.SpamException
	{
		if (subject == null)
			return;

		// Removes duplicated space chars
		subject = subject.replaceAll("[ ]+"," ");
		for (Rule rule : RULES) {
			try {
				rule.checkSubject(subject);
			} catch (ModelException.SpamException e) {
				DailyNumber.blockedSpams.inc();
				if (request != null)
					logger.info("host="+request.getServerName()+" | IP=" + Jtp.getClientIpAddr(request) + " | " + e.getMessage());
				else
					logger.info("Blocked Mail | " + e.getMessage());
				throw e;
			}
		}
	}

	public static void checkMessage(HttpServletRequest request, String message, Person visitor)
		throws ModelException.SpamException
	{
		if (message == null)
			return;

		// Removes duplicated space chars
		message = message.replaceAll("[ ]+"," ");
		for (Rule rule : RULES) {
			try {
				rule.checkMessage(message, visitor);
			} catch (ModelException.SpamException e) {
				DailyNumber.blockedSpams.inc();
				String email = visitor instanceof User? ((User) visitor).getEmail() : "NO EMAIL";
				if (request != null)
					logger.info("host="+request.getServerName()+" | IP=" + Jtp.getClientIpAddr(request) + " | " + email + " | " + e.getMessage());
				else
					logger.info("Blocked Mail | " + email + " | " + e.getMessage());
				throw e;
			}
		}
	}
*/
	protected void service(HttpServletRequest request,HttpServletResponse response)
		throws ServletException, IOException
	{
		String spamRules = SystemProperties.get("spam.rules");

		if ("save".equals(request.getParameter("action"))) {
			String rules = request.getParameter("rules");
			RULES.clear();
			if (rules != null && rules.length() > 0) {
				List<Rule> r = parseRules(rules);
				if (r.size() > 0)
					RULES.addAll(r);
			}
			SystemProperties.set("spam.rules", rules);
			response.sendRedirect("/tools/");
			return;
		}

		PrintWriter out = response.getWriter();
		
		out.print( "\n<html>\n	<head>\n		<script src=\"" );
		out.print( (Shared.getJQueryPath()) );
		out.print( "\"></script>\n		<link rel=\"stylesheet\" href=\"" );
		out.print( (Shared.getCssPath()) );
		out.print( "\" type=\"text/css\" />\n	</head>\n	<body>\n		<div>\n			<a href=\"/tools/\">Tools</a>\n		</div>\n		<h1>Spam Rules</h1>\n		<div id=\"nabble\" class=\"nabble\">\n			<form action=\"/tools/SpamRules.jtp\" method=\"POST\">\n				<input type=\"hidden\" name=\"action\" value=\"save\">\n				<textarea name=\"rules\" rows=15 style=\"width:80%\">" );
		out.print( (Jtp.hideNull(spamRules)) );
		out.print( "</textarea>\n				<br>\n				<input type=\"submit\" value=\"Save Rules\">\n			</form>\n		</div>\n	</body>\n</html>\n" );

	}

	private static synchronized List<Rule> parseRules(String rules) {
		List<Rule> r = new ArrayList<Rule>();
		String[] lines = rules.split("\n");
		for (String line : lines) {
			if (line.length() == 0 || line.startsWith("#")) {
				// do nothing
			} else if (line.startsWith("subject-contains:"))
				r.add(new SubjectContainsRule(line.substring("subject-contains:".length()).trim()));
			else if (line.startsWith("message-contains:"))
				r.add(new MessageContainsRule(line.substring("message-contains:".length()).trim()));
			else if (line.startsWith("message-contains-pattern:"))
				r.add(new MessageContainsPattern(line.substring("message-contains-pattern:".length()).trim()));
			else if (line.startsWith("message-word-count:"))
				r.add(new WordCountRule(line.substring("message-word-count:".length()).trim()));
			else if (line.startsWith("subject-max-words:"))
				r.add(new SubjectMaxWordsRule(line.substring("subject-max-words:".length()).trim()));
			else if (line.startsWith("message-max-words:"))
				r.add(new MessageMaxWordsRule(line.substring("message-max-words:".length()).trim()));
			else if (line.startsWith("user-email-pattern:"))
				r.add(new UserEmailPattern(line.substring("user-email-pattern:".length()).trim()));
		}
		return r;
	}

	private static class SubjectContainsRule implements Rule {
		private String text;
		private String[] parts;
		public SubjectContainsRule(String text) {
			this.text = text;
			this.parts = text.toLowerCase().split("\\+");
		}
		public String checkSubject(String subject)
			throws ModelException.SpamException
		{
			if (subject == null) return null;
			subject = subject.toLowerCase();
			for (String part : parts) {
				if (subject.indexOf(part) == -1)
					return null;
			}
			throw new ModelException.SubjectContainsInvalidWord(text);
		}
		public String checkMessage(String message, Person visitor) { return null; }
	}

	private static class SubjectMaxWordsRule implements Rule {
		private int max;
		private String[] parts;
		public SubjectMaxWordsRule(String text) {
			String[] params = text.split("\\|");
			this.max = Integer.valueOf(params[0]);
			this.parts = params[1].toLowerCase().split("\\+");
		}
		public String checkSubject(String subject)
			throws ModelException.SpamException
		{
			if (subject == null) return null;
			subject = subject.toLowerCase();
			int count = 0;
			for (String part : parts) {
				if (subject.indexOf(part) >= 0)
					count++;
				if (count >= max)
					throw new ModelException.SubjectContainsCommonSpamWords(subject);
			}
			return null;
		}
		public String checkMessage(String message, Person visitor) { return null; }
	}

	private static class MessageMaxWordsRule implements Rule {
		private int max;
		private String[] parts;
		public MessageMaxWordsRule(String text) {
			String[] params = text.split("\\|");
			this.max = Integer.valueOf(params[0]);
			this.parts = params[1].toLowerCase().split("\\+");
		}
		public String checkMessage(String message, Person visitor)
			throws ModelException.SpamException
		{
			if (message == null) return null;
			message = message.toLowerCase();
			int count = 0;
			for (String part : parts) {
				if (message.indexOf(part) >= 0)
					count++;
				if (count >= max)
					throw new ModelException.MessageContainsCommonSpamWords(message);
			}
			return null;
		}
		public String checkSubject(String subject) { return null; }
	}

	private static class MessageContainsRule implements Rule {
		private String text;
		private String[] parts;
		public MessageContainsRule(String text) {
			this.text = text;
			this.parts = text.toLowerCase().split("\\+");
		}
		public String checkMessage(String message, Person visitor)
			throws ModelException.SpamException
		{
			if (message == null) return null;
			String msg = message.toLowerCase();
			for (String part : parts) {
				if (msg.indexOf(part) == -1)
					return null;
			}
			throw new ModelException.MessageContainsInvalidWord(text);
		}
		public String checkSubject(String subject) { return null; }
	}

	private static class MessageContainsPattern implements Rule {
		private Pattern[] pattern;
		public MessageContainsPattern(String patternList) {
			String[] patterns = patternList.split("____");
			this.pattern = new Pattern[patterns.length];
			for (int i = 0; i < patterns.length; i++)
				this.pattern[i] = Pattern.compile(patterns[i]);
		}
		public String checkMessage(String message, Person visitor)
			throws ModelException.SpamException
		{
			if (message == null) return null;
			for (Pattern p : pattern) {
				if (!p.matcher(message).find())
					return null;
			}
			throw new ModelException.MessageContainsCommonSpamWords(message);
		}
		public String checkSubject(String subject) { return null; }
	}

	private static class UserEmailPattern implements Rule {
		private Pattern pattern;
		public UserEmailPattern(String pattern) {
			this.pattern = Pattern.compile(pattern);
		}
		public String checkMessage(String message, Person visitor)
			throws ModelException.SpamException
		{
			if (visitor instanceof User) {
				String email = ((User) visitor).getEmail();
				if (!pattern.matcher(email).matches())
					return null;
				throw new ModelException.MessageContainsInvalidWord("EMAIL: " + email);
			}
			return null;
		}
		public String checkSubject(String subject) { return null; }
	}

	private static class WordCountRule implements Rule {
		private String text;
		private int count;
		public WordCountRule(String value) {
			String[] values = value.split(">");
			this.text = values[0].toLowerCase();
			this.count = Integer.valueOf(values[1]);
		}
		public String checkMessage(String message, Person visitor)
			throws ModelException.SpamException
		{
			if (message == null) return null;
			String msg = message.toLowerCase();
			int oldPos = 0;
			int newPos = msg.indexOf(text);
			int c = 0;
			while (newPos > oldPos) {
				c++;
				if (c >= count)
					throw new ModelException.MessageContainsManyInvalidWords(text);
				oldPos = newPos;
				newPos = msg.indexOf(text, oldPos+text.length());
			}
			return null;
		}
		public String checkSubject(String subject) { return null; }
	}
}