FEATURE: roll up function for 123.456.789.* ranges

This commit is contained in:
Régis Hanol 2014-11-24 17:25:48 +01:00
parent a91d5fc726
commit 1023191315
10 changed files with 104 additions and 10 deletions

View File

@ -14,6 +14,14 @@ export default Ember.ArrayController.extend(Discourse.Presence, {
actions: { actions: {
recordAdded: function(arg) { recordAdded: function(arg) {
this.get("model").unshiftObject(arg); this.get("model").unshiftObject(arg);
},
rollUp: function() {
var self = this;
this.set("loading", true)
return Discourse.ScreenedIpAddress.rollUp().then(function() {
self.send("show");
});
} }
} }
}); });

View File

@ -51,5 +51,9 @@ Discourse.ScreenedIpAddress.reopenClass({
return Discourse.ScreenedIpAddress.create(b); return Discourse.ScreenedIpAddress.create(b);
}); });
}); });
},
rollUp: function() {
return Discourse.ajax("/admin/logs/screened_ip_addresses/roll_up", { type: "POST" });
} }
}); });

View File

@ -1,5 +1,5 @@
<p>{{i18n admin.logs.screened_ips.description}}</p> <p>{{i18n admin.logs.screened_ips.description}}</p>
<button class="btn pull-right" {{action "rollUp"}} title="{{i18n admin.logs.screened_ips.roll_up.title}}">{{i18n admin.logs.screened_ips.roll_up.text}}</button>
{{screened-ip-address-form action="recordAdded"}} {{screened-ip-address-form action="recordAdded"}}
<br/> <br/>

View File

@ -1,4 +1,4 @@
<b>{{i18n admin.logs.screened_ips.form.label}}</b> <b>{{i18n admin.logs.screened_ips.form.label}}</b>
{{text-field value=ip_address disabled=formSubmitted class="ip-address-input" placeholderKey="admin.logs.screened_ips.form.ip_address" autocorrect="off" autocapitalize="off"}} {{text-field value=ip_address disabled=formSubmitted class="ip-address-input" placeholderKey="admin.logs.screened_ips.form.ip_address" autocorrect="off" autocapitalize="off"}}
{{combo-box content=actionNames value=actionName}} {{combo-box content=actionNames value=actionName}}
<button class="btn btn-small" {{action "submit" target="view"}} {{bind-attr disabled="formSubmitted"}}>{{i18n admin.logs.screened_ips.form.add}}</button> <button class="btn" {{action "submit" target="view"}} {{bind-attr disabled="formSubmitted"}}>{{i18n admin.logs.screened_ips.form.add}}</button>

View File

@ -29,6 +29,58 @@ class Admin::ScreenedIpAddressesController < Admin::AdminController
render json: success_json render json: success_json
end end
def roll_up
# 1 - retrieve all subnets that needs roll up
sql = <<-SQL
SELECT network(inet(host(ip_address) || './24')) AS ip_range
FROM screened_ip_addresses
WHERE action_type = :action_type
AND family(ip_address) = 4
AND masklen(ip_address) = 32
GROUP BY ip_range
HAVING COUNT(*) >= :min_count
SQL
subnets = ScreenedIpAddress.exec_sql(sql,
action_type: ScreenedIpAddress.actions[:block],
min_count: SiteSetting.min_ban_entries_for_roll_up).values.flatten
subnets.each do |subnet|
# 2 - create subnet if not already exists
ScreenedIpAddress.new(ip_address: subnet).save unless ScreenedIpAddress.where(ip_address: subnet).first
# 3 - update stats
sql = <<-SQL
UPDATE screened_ip_addresses
SET match_count = sum_match_count,
created_at = min_created_at,
last_match_at = max_last_match_at
FROM (
SELECT SUM(match_count) AS sum_match_count,
MIN(created_at) AS min_created_at,
MAX(last_match_at) AS max_last_match_at
FROM screened_ip_addresses
WHERE action_type = :action_type
AND family(ip_address) = 4
AND masklen(ip_address) = 32
AND ip_address << :ip_address
) s
WHERE ip_address = :ip_address
SQL
ScreenedIpAddress.exec_sql(sql, action_type: ScreenedIpAddress.actions[:block], ip_address: subnet)
# 4 - remove old matches
ScreenedIpAddress.where(action_type: ScreenedIpAddress.actions[:block])
.where("family(ip_address) = 4")
.where("masklen(ip_address) = 32")
.where("ip_address << ?", subnet)
.delete_all
end
render json: success_json
end
private private
def allowed_params def allowed_params

View File

@ -1870,6 +1870,9 @@ en:
label: "New:" label: "New:"
ip_address: "IP address" ip_address: "IP address"
add: "Add" add: "Add"
roll_up:
text: "Roll up"
title: "Creates new subnet ban entries if there are at least 'min_ban_entries_for_roll_up' entries."
logster: logster:
title: "Error Logs" title: "Error Logs"

View File

@ -942,6 +942,7 @@ en:
levenshtein_distance_spammer_emails: "When matching spammer emails, number of characters difference that will still allow a fuzzy match." levenshtein_distance_spammer_emails: "When matching spammer emails, number of characters difference that will still allow a fuzzy match."
max_new_accounts_per_registration_ip: "If there are already (n) trust level 0 accounts from this IP (and none is a staff member or at TL2 or higher), stop accepting new signups from that IP." max_new_accounts_per_registration_ip: "If there are already (n) trust level 0 accounts from this IP (and none is a staff member or at TL2 or higher), stop accepting new signups from that IP."
min_ban_entries_for_roll_up: "When clicking the Roll up button, will create a new subnet ban entry if there are at least (N) entries."
reply_by_email_enabled: "Enable replying to topics via email." reply_by_email_enabled: "Enable replying to topics via email."
reply_by_email_address: "Template for reply by email incoming email address, for example: %{reply_key}@reply.example.com or replies+%{reply_key}@example.com" reply_by_email_address: "Template for reply by email incoming email address, for example: %{reply_key}@reply.example.com or replies+%{reply_key}@example.com"

View File

@ -101,7 +101,11 @@ Discourse::Application.routes.draw do
scope "/logs" do scope "/logs" do
resources :staff_action_logs, only: [:index] resources :staff_action_logs, only: [:index]
resources :screened_emails, only: [:index, :destroy] resources :screened_emails, only: [:index, :destroy]
resources :screened_ip_addresses, only: [:index, :create, :update, :destroy] resources :screened_ip_addresses, only: [:index, :create, :update, :destroy] do
collection do
post "roll_up"
end
end
resources :screened_urls, only: [:index] resources :screened_urls, only: [:index]
end end

View File

@ -577,6 +577,7 @@ spam:
min: 0 min: 0
max: 3 max: 3
max_new_accounts_per_registration_ip: 3 max_new_accounts_per_registration_ip: 3
min_ban_entries_for_roll_up: 5
rate_limits: rate_limits:
unique_posts_mins: unique_posts_mins:

View File

@ -1,6 +1,7 @@
require 'spec_helper' require 'spec_helper'
describe Admin::ScreenedIpAddressesController do describe Admin::ScreenedIpAddressesController do
it "is a subclass of AdminController" do it "is a subclass of AdminController" do
(Admin::ScreenedIpAddressesController < Admin::AdminController).should == true (Admin::ScreenedIpAddressesController < Admin::AdminController).should == true
end end
@ -8,15 +9,35 @@ describe Admin::ScreenedIpAddressesController do
let!(:user) { log_in(:admin) } let!(:user) { log_in(:admin) }
describe 'index' do describe 'index' do
before do
xhr :get, :index
end
subject { response }
it { should be_success }
it 'returns JSON' do it 'returns JSON' do
::JSON.parse(subject.body).should be_a(Array) xhr :get, :index
response.should be_success
JSON.parse(response.body).should be_a(Array)
end end
end end
describe 'roll_up' do
it "works" do
SiteSetting.expects(:min_ban_entries_for_roll_up).returns(3)
Fabricate(:screened_ip_address, ip_address: "1.2.3.4", match_count: 1)
Fabricate(:screened_ip_address, ip_address: "1.2.3.5", match_count: 1)
Fabricate(:screened_ip_address, ip_address: "1.2.3.6", match_count: 1)
Fabricate(:screened_ip_address, ip_address: "42.42.42.4", match_count: 1)
Fabricate(:screened_ip_address, ip_address: "42.42.42.5", match_count: 1)
xhr :post, :roll_up
response.should be_success
subnet = ScreenedIpAddress.where(ip_address: "1.2.3.0/24").first
subnet.should be_present
subnet.match_count.should == 3
end
end
end end