1 package mircoders.global;
\r
3 import java.io.FileNotFoundException;
\r
4 import java.util.Arrays;
\r
5 import java.util.Date;
\r
6 import java.util.HashMap;
\r
7 import java.util.Iterator;
\r
8 import java.util.List;
\r
9 import java.util.Map;
\r
10 import java.util.Vector;
\r
11 import java.util.Random;
\r
13 import javax.servlet.http.*;
\r
15 import org.apache.commons.collections.*;
\r
16 import gnu.regexp.RE;
\r
18 import mir.log.LoggerWrapper;
\r
19 import mir.util.DateToMapAdapter;
\r
20 import mir.util.StringRoutines;
\r
22 import mir.entity.*;
\r
24 import mircoders.entity.EntityComment;
\r
25 import mircoders.entity.EntityContent;
\r
26 import mircoders.localizer.MirAdminInterfaceLocalizer;
\r
29 public class Abuse {
\r
30 private List filters;
\r
31 private int maxIdentifier;
\r
32 private LoggerWrapper logger;
\r
33 private int logSize;
\r
34 private boolean logEnabled;
\r
35 private boolean openPostingDisabled;
\r
36 private boolean openPostingPassword;
\r
37 private boolean cookieOnBlock;
\r
38 private String articleBlockAction;
\r
39 private String commentBlockAction;
\r
41 private String configFile = MirGlobal.config().getStringWithHome("Abuse.Config");
\r
44 private static final String IP_FILTER_TYPE="ip";
\r
45 private static final String REGEXP_FILTER_TYPE="regexp";
\r
46 private static String cookieName=MirGlobal.config().getString("Abuse.CookieName");
\r
47 private static int cookieMaxAge = 60*60*MirGlobal.config().getInt("Abuse.CookieMaxAge");
\r
50 logger = new LoggerWrapper("Global.Abuse");
\r
51 filters = new Vector();
\r
57 articleBlockAction = "";
\r
58 commentBlockAction = "";
\r
59 openPostingPassword = false;
\r
60 openPostingDisabled = false;
\r
61 cookieOnBlock = false;
\r
66 public boolean checkIpFilter(String anIpAddress) {
\r
67 synchronized (filters) {
\r
68 Iterator i = filters.iterator();
\r
70 while (i.hasNext()) {
\r
71 Filter filter = (Filter) i.next();
\r
74 if ( (filter.getType().equals(IP_FILTER_TYPE)) &&
\r
75 InternetFunctions.isIpAddressInNetwork(anIpAddress, filter.getExpression())) {
\r
76 logger.debug("ip match on " + filter.getExpression());
\r
80 catch (Throwable t) {
\r
81 logger.warn("error while checking ip address " + anIpAddress + " over network " + filter.expression + ": " + t.getMessage());
\r
89 private boolean checkRegExpFilter(Entity anEntity) {
\r
90 synchronized (filters) {
\r
91 Iterator i = filters.iterator();
\r
93 while (i.hasNext()) {
\r
94 Filter filter = (Filter) i.next();
\r
96 if (filter.getType().equals(REGEXP_FILTER_TYPE)) {
\r
98 RE regularExpression = new RE(filter.getExpression());
\r
100 Iterator j = anEntity.getFields().iterator();
\r
101 while (j.hasNext()) {
\r
102 String field = anEntity.getValue( (String) j.next());
\r
104 if (field != null && regularExpression.isMatch(field.toLowerCase())) {
\r
105 logger.debug("regexp match on " + filter.getExpression());
\r
110 catch (Throwable t) {
\r
111 logger.warn("error while checking entity with regexp " + filter.getExpression() + ": " + t.getMessage());
\r
120 private void setCookie(HttpServletResponse aResponse) {
\r
121 Random random = new Random();
\r
123 Cookie cookie = new Cookie(cookieName, Integer.toString(random.nextInt(1000000000)));
\r
124 cookie.setMaxAge(cookieMaxAge);
\r
125 cookie.setPath("/");
\r
126 aResponse.addCookie(cookie);
\r
129 private boolean checkCookie(List aCookies) {
\r
130 if (getCookieOnBlock()) {
\r
131 Iterator i = aCookies.iterator();
\r
133 while (i.hasNext()) {
\r
134 Cookie cookie = (Cookie) i.next();
\r
136 if (cookie.getName().equals(cookieName)) {
\r
137 logger.debug("cookie match");
\r
146 public void checkComment(EntityComment aComment, HttpServletRequest aRequest, HttpServletResponse aResponse) {
\r
148 long time = System.currentTimeMillis();
\r
150 MirAdminInterfaceLocalizer.MirSimpleEntityOperation operation = MirGlobal.localizer().adminInterface().simpleCommentOperationForName(commentBlockAction);
\r
152 if (checkCookie(Arrays.asList(aRequest.getCookies())) || checkIpFilter(aRequest.getRemoteAddr()) || checkRegExpFilter(aComment)) {
\r
153 operation.perform(null, MirGlobal.localizer().dataModel().adapterModel().makeEntityAdapter("comment", aComment));
\r
154 setCookie(aResponse);
\r
157 logger.info("checkComment: " + (System.currentTimeMillis()-time) + "ms");
\r
160 catch (Throwable t) {
\r
161 logger.error("Abuse.checkComment: " + t.toString());
\r
165 public void checkArticle(EntityContent anArticle, HttpServletRequest aRequest, HttpServletResponse aResponse) {
\r
167 long time = System.currentTimeMillis();
\r
169 MirAdminInterfaceLocalizer.MirSimpleEntityOperation operation = MirGlobal.localizer().adminInterface().simpleCommentOperationForName(commentBlockAction);
\r
171 if (checkCookie(Arrays.asList(aRequest.getCookies())) || checkIpFilter(aRequest.getRemoteAddr()) || checkRegExpFilter(anArticle)) {
\r
172 operation.perform(null, MirGlobal.localizer().dataModel().adapterModel().makeEntityAdapter("content", anArticle));
\r
173 setCookie(aResponse);
\r
176 logger.info("checkArticle: " + (System.currentTimeMillis()-time) + "ms");
\r
178 catch (Throwable t) {
\r
179 logger.error("Abuse.checkArticle: " + t.toString());
\r
183 public boolean getLogEnabled() {
\r
187 public void setLogEnabled(boolean anEnabled) {
\r
188 logEnabled = anEnabled;
\r
192 public int getLogSize() {
\r
196 public void setLogSize(int aSize) {
\r
201 public boolean getOpenPostingDisabled() {
\r
202 return openPostingDisabled;
\r
205 public void setOpenPostingDisabled(boolean anOpenPostingDisabled) {
\r
206 openPostingDisabled = anOpenPostingDisabled;
\r
209 public boolean getOpenPostingPassword() {
\r
210 return openPostingPassword;
\r
213 public void setOpenPostingPassword(boolean anOpenPostingPassword) {
\r
214 openPostingPassword = anOpenPostingPassword;
\r
217 public boolean getCookieOnBlock() {
\r
218 return cookieOnBlock;
\r
221 public void setCookieOnBlock(boolean aCookieOnBlock) {
\r
222 cookieOnBlock = aCookieOnBlock;
\r
225 public String getArticleBlockAction() {
\r
226 return articleBlockAction;
\r
229 public void setArticleBlockAction(String anAction) {
\r
230 articleBlockAction = anAction;
\r
233 public String getCommentBlockAction() {
\r
234 return commentBlockAction;
\r
237 public void setCommentBlockAction(String anAction) {
\r
238 commentBlockAction = anAction;
\r
242 public List getLog() {
\r
243 synchronized(log) {
\r
244 List result = new Vector();
\r
246 Iterator i = log.iterator();
\r
247 while (i.hasNext()) {
\r
248 LogEntry logEntry = (LogEntry) i.next();
\r
249 Map entry = new HashMap();
\r
251 entry.put("ip", logEntry.getIpNumber());
\r
252 entry.put("id", logEntry.getId());
\r
253 entry.put("timestamp", new DateToMapAdapter(logEntry.getTimeStamp()));
\r
254 if (logEntry.getIsArticle())
\r
255 entry.put("type", "content");
\r
257 entry.put("type", "comment");
\r
258 entry.put("browser", logEntry.getBrowserString());
\r
267 public void logComment(String anIp, String anId, Date aTimeStamp, String aBrowser) {
\r
268 appendLog(new LogEntry(aTimeStamp, anIp, aBrowser, anId, false));
\r
271 public void logArticle(String anIp, String anId, Date aTimeStamp, String aBrowser) {
\r
272 appendLog(new LogEntry(aTimeStamp, anIp, aBrowser, anId, true));
\r
275 public void load() {
\r
277 ExtendedProperties configuration = new ExtendedProperties();
\r
280 configuration = new ExtendedProperties(configFile);
\r
282 catch (FileNotFoundException e) {
\r
285 getFilterConfig(filters, "abuse.filter", configuration);
\r
287 setOpenPostingDisabled(configuration.getString("abuse.openPostingDisabled", "0").equals("1"));
\r
288 setOpenPostingPassword(configuration.getString("abuse.openPostingPassword", "0").equals("1"));
\r
289 setCookieOnBlock(configuration.getString("abuse.cookieOnBlock", "0").equals("1"));
\r
290 setLogEnabled(configuration.getString("abuse.logEnabled", "0").equals("1"));
\r
291 setLogSize(configuration.getInt("abuse.logSize", 10));
\r
292 setArticleBlockAction(configuration.getString("abuse.articleBlockAction", ""));
\r
293 setCommentBlockAction(configuration.getString("abuse.commentBlockAction", ""));
\r
295 catch (Throwable t) {
\r
296 throw new RuntimeException(t.toString());
\r
299 public void save() {
\r
301 ExtendedProperties configuration = new ExtendedProperties();
\r
303 setFilterConfig(filters, "abuse.filter", configuration);
\r
305 configuration.addProperty("abuse.openPostingDisabled", getOpenPostingDisabled()?"1":"0");
\r
306 configuration.addProperty("abuse.openPostingPassword", getOpenPostingPassword()?"1":"0");
\r
307 configuration.addProperty("abuse.cookieOnBlock", getCookieOnBlock()?"1":"0");
\r
308 configuration.addProperty("abuse.logEnabled", getLogEnabled()?"1":"0");
\r
309 configuration.addProperty("abuse.logSize", Integer.toString(getLogSize()));
\r
310 configuration.addProperty("abuse.articleBlockAction", getArticleBlockAction());
\r
311 configuration.addProperty("abuse.commentBlockAction", getCommentBlockAction());
\r
313 configuration.save(new FileOutputStream(new File(configFile)), "Anti abuse configuration");
\r
315 catch (Throwable t) {
\r
316 throw new RuntimeException(t.toString());
\r
320 public List getFilterTypes() {
\r
321 List result = new Vector();
\r
323 Map entry = new HashMap();
\r
324 entry.put("resource", "abuse.filtertype.ip");
\r
325 entry.put("id", IP_FILTER_TYPE);
\r
328 entry = new HashMap();
\r
329 entry.put("resource", "abuse.filtertype.regexp");
\r
330 entry.put("id", REGEXP_FILTER_TYPE);
\r
336 public List getArticleActions() {
\r
338 List result = new Vector();
\r
340 Iterator i = MirGlobal.localizer().adminInterface().simpleArticleOperations().iterator();
\r
341 while (i.hasNext()) {
\r
342 MirAdminInterfaceLocalizer.MirSimpleEntityOperation operation =
\r
343 (MirAdminInterfaceLocalizer.MirSimpleEntityOperation) i.next();
\r
345 Map action = new HashMap();
\r
346 action.put("resource", "content.operation."+operation.getName());
\r
347 action.put("identifier", operation.getName());
\r
349 result.add(action);
\r
354 catch (Throwable t) {
\r
355 throw new RuntimeException("can't get article actions");
\r
359 public List getCommentActions() {
\r
361 List result = new Vector();
\r
363 Iterator i = MirGlobal.localizer().adminInterface().simpleCommentOperations().iterator();
\r
364 while (i.hasNext()) {
\r
365 MirAdminInterfaceLocalizer.MirSimpleEntityOperation operation =
\r
366 (MirAdminInterfaceLocalizer.MirSimpleEntityOperation) i.next();
\r
368 Map action = new HashMap();
\r
369 action.put("resource", "comment.operation."+operation.getName());
\r
370 action.put("identifier", operation.getName());
\r
372 result.add(action);
\r
377 catch (Throwable t) {
\r
378 throw new RuntimeException("can't get comment actions");
\r
382 public List getFilters() {
\r
383 return getFiltersAsMaps(filters);
\r
386 public void addFilter(String aType, String anExpression) {
\r
387 addFilter(filters, aType, anExpression);
\r
390 public void setFilter(String anIdentifier, String aType, String anExpression) {
\r
391 setFilter(filters, anIdentifier, aType, anExpression);
\r
394 public void deleteFilter(String anIdentifier) {
\r
395 deleteFilter(filters, anIdentifier);
\r
398 public void validateIpFilter(String anIdentifier, String anArticleAction, String aCommentAction) throws Exception {
\r
401 private List getFiltersAsMaps(List aFilters) {
\r
402 synchronized(aFilters) {
\r
403 List result = new Vector();
\r
405 Iterator i = aFilters.iterator();
\r
406 while (i.hasNext()) {
\r
407 Filter filter = (Filter) i.next();
\r
408 Map map = new HashMap();
\r
410 map.put("id", filter.getId());
\r
411 map.put("expression", filter.getExpression());
\r
412 map.put("type", filter.getType());
\r
420 private void addFilter(List aFilters, String aType, String anExpression) {
\r
421 Filter filter = new Filter();
\r
423 filter.setId(generateId());
\r
424 filter.setExpression(anExpression);
\r
425 filter.setType(aType);
\r
427 synchronized (aFilters) {
\r
428 aFilters.add(filter);
\r
432 private void setFilter(List aFilters, String anIdentifier, String aType, String anExpression) {
\r
433 synchronized (aFilters) {
\r
434 Filter filter = findFilter(aFilters, anIdentifier);
\r
436 if (filter!=null) {
\r
437 filter.setExpression(anExpression);
\r
438 filter.setType(aType);
\r
443 private Filter findFilter(List aFilters, String anIdentifier) {
\r
444 synchronized (aFilters) {
\r
445 Iterator i = aFilters.iterator();
\r
446 while (i.hasNext()) {
\r
447 Filter filter = (Filter) i.next();
\r
449 if (filter.getId().equals(anIdentifier)) {
\r
458 private void deleteFilter(List aFilters, String anIdentifier) {
\r
459 synchronized (aFilters) {
\r
460 Filter filter = findFilter(aFilters, anIdentifier);
\r
462 if (filter!=null) {
\r
463 aFilters.remove(filter);
\r
468 private String generateId() {
\r
469 synchronized(this) {
\r
470 maxIdentifier = maxIdentifier+1;
\r
472 return Integer.toString(maxIdentifier);
\r
476 private static class Filter {
\r
477 private String identifier;
\r
478 private String expression;
\r
479 private String type;
\r
487 public String getId() {
\r
491 public void setId(String anId) {
\r
495 public String getExpression() {
\r
499 public void setExpression(String anExpression) {
\r
500 expression = anExpression;
\r
503 public String getType() {
\r
507 public void setType(String aType) {
\r
512 private void setFilterConfig(List aFilters, String aConfigKey, ExtendedProperties aConfiguration) {
\r
513 synchronized(aFilters) {
\r
514 Iterator i = aFilters.iterator();
\r
516 while (i.hasNext()) {
\r
517 Filter filter = (Filter) i.next();
\r
519 aConfiguration.addProperty(aConfigKey, filter.getType()+":"+filter.getExpression());
\r
524 private void getFilterConfig(List aFilters, String aConfigKey, ExtendedProperties aConfiguration) {
\r
525 synchronized(aFilters) {
\r
528 Iterator i = Arrays.asList(aConfiguration.getStringArray(aConfigKey)).iterator();
\r
530 while (i.hasNext()) {
\r
531 String filter = (String) i.next();
\r
532 List parts = StringRoutines.separateString(filter, ":");
\r
534 if (parts.size()==2) {
\r
535 addFilter( (String) parts.get(0), (String) parts.get(1));
\r
541 private static class LogEntry {
\r
542 private String ipNumber;
\r
543 private String browserString;
\r
545 private Date timeStamp;
\r
546 private boolean isArticle;
\r
548 public LogEntry(Date aTimeStamp, String anIpNumber, String aBrowserString, String anId, boolean anIsArticle) {
\r
549 ipNumber = anIpNumber;
\r
550 browserString = aBrowserString;
\r
552 isArticle = anIsArticle;
\r
553 timeStamp=aTimeStamp;
\r
556 public String getIpNumber() {
\r
560 public String getBrowserString() {
\r
561 return browserString;
\r
564 public String getId() {
\r
568 public Date getTimeStamp() {
\r
572 public boolean getIsArticle() {
\r
577 private void truncateLog() {
\r
578 synchronized(log) {
\r
582 while (log.size()>0 && log.size()>logSize) {
\r
589 private void appendLog(LogEntry anEntry) {
\r
590 synchronized (log) {
\r