Changesets can be listed by changeset number.
The Git repository is here.
- Revision:
- 15
- Log:
Attempt to update Typo to a Typo SVN HEAD release from around the
time the prototype installation was set up on the RISC OS Open Limited
web site. Timestamps place this at 04-Jul so a revision from 05-Jul or
earlier was pulled and copied over the 2.6.0 tarball stable code.
- Author:
- adh
- Date:
- Sat Jul 22 23:27:35 +0100 2006
- Size:
- 3745 Bytes
1 | class SpamProtection |
2 | |
3 | IP_RBLS = [ 'opm.blitzed.us', 'bsb.empty.us' ] |
4 | HOST_RBLS = [ 'multi.surbl.org', 'bsb.empty.us' ] |
5 | SECOND_LEVEL = [ 'co', 'com', 'net', 'org', 'gov' ] |
6 | |
7 | attr_accessor :this_blog |
8 | |
9 | def initialize(a_blog) |
10 | self.this_blog = a_blog |
11 | end |
12 | |
13 | def article_closed?(record) |
14 | return false if this_blog.sp_article_auto_close.zero? or not record.new_record? |
15 | |
16 | if record.article.created_at.to_i < this_blog.sp_article_auto_close.days.ago.to_i |
17 | logger.info("[SP] Blocked interaction with #{record.article.title}") |
18 | return true |
19 | end |
20 | end |
21 | |
22 | def is_spam?(string) |
23 | return false unless this_blog.sp_global |
24 | return false if string.blank? |
25 | |
26 | reason = catch(:hit) do |
27 | case string |
28 | when Format::IP_ADDRESS: self.scan_ip(string) |
29 | when Format::HTTP_URI: self.scan_uri(URI.parse(string).host) rescue URI::InvalidURIError |
30 | else self.scan_text(string) |
31 | end |
32 | end |
33 | |
34 | if reason |
35 | logger.info("[SP] Hit: #{reason}") |
36 | return true |
37 | end |
38 | end |
39 | |
40 | protected |
41 | |
42 | def scan_ip(ip_address) |
43 | logger.info("[SP] Scanning IP #{ip_address}") |
44 | query_rbls(IP_RBLS, ip_address.split('.').reverse.join('.')) |
45 | end |
46 | |
47 | def scan_text(string) |
48 | # Scan contained URLs |
49 | uri_list = string.scan(/(http:\/\/[^\s"]+)/m).flatten |
50 | |
51 | # Check for URL count limit |
52 | if this_blog.sp_url_limit > 0 |
53 | throw :hit, "Hard URL Limit hit: #{uri_list.size} > #{this_blog.sp_url_limit}" if uri_list.size > this_blog.sp_url_limit |
54 | end |
55 | |
56 | uri_list.collect { |uri| URI.parse(uri).host rescue nil }.uniq.compact.each do |host| |
57 | scan_uri(host) |
58 | end |
59 | |
60 | # Pattern scanning |
61 | BlacklistPattern.find_all.each do |pattern| |
62 | logger.info("[SP] Scanning for #{pattern.class} #{pattern.pattern}") |
63 | |
64 | throw :hit, "#{pattern} matched" if pattern.matches?(string) |
65 | end |
66 | |
67 | return false |
68 | end |
69 | |
70 | def scan_uri(host) |
71 | return scan_ip(host) if host =~ Format::IP_ADDRESS |
72 | |
73 | host_parts = host.split('.').reverse |
74 | domain = Array.new |
75 | |
76 | # Check for two level TLD |
77 | (SECOND_LEVEL.include?(host_parts[1]) ? 3:2).times do |
78 | domain.unshift(host_parts.shift) |
79 | end |
80 | |
81 | logger.info("[SP] Scanning domain #{domain.join('.')}") |
82 | query_rbls(HOST_RBLS, host, domain.join('.')) |
83 | end |
84 | |
85 | def query_rbls(rbls, *subdomains) |
86 | rbls.each do |rbl| |
87 | subdomains.uniq.each do |d| |
88 | begin |
89 | response = IPSocket.getaddress([d, rbl].join('.')) |
90 | throw :hit, "#{rbl} positively resolved subdomain #{d} => #{response}" if response =~ /^127\.0\.0\./ |
91 | rescue SocketError |
92 | # NXDOMAIN response => negative: d is not in RBL |
93 | end |
94 | end |
95 | end |
96 | return false |
97 | end |
98 | |
99 | def logger |
100 | @logger ||= RAILS_DEFAULT_LOGGER || Logger.new(STDOUT) |
101 | end |
102 | end |
103 | |
104 | module ActiveRecord |
105 | module Validations |
106 | module ClassMethods |
107 | def validates_against_spamdb(*attr_names) |
108 | configuration = { :message => "blocked by SpamProtection" } |
109 | configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash) |
110 | |
111 | validates_each(attr_names, configuration) do |record, attr_name, value| |
112 | record.errors.add(attr_name, configuration[:message]) if SpamProtection.new(record.blog).is_spam?(value) |
113 | end |
114 | end |
115 | def validates_age_of(*attr_names) |
116 | configuration = { :on => :create, :message => "points to an item that is no longer available for interaction"} |
117 | configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash) |
118 | |
119 | validates_each(attr_names, configuration) do |record, attr_name, value| |
120 | next unless value.to_i > 0 |
121 | record.errors.add(attr_name, configuration[:message]) if SpamProtection.new(record.blog).article_closed?(record) |
122 | end |
123 | end |
124 | end |
125 | end |
126 | end |