From c4e427cf73b6ec24bdcf753c967e78106fa18f30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Tue, 10 Feb 2015 19:38:59 +0100 Subject: [PATCH] FEATURE: filter screened IP addresses --- .../admin-logs-screened-ip-addresses.js.es6 | 7 +++--- .../admin/models/screened_ip_address.js | 4 +-- .../templates/logs/screened_ip_addresses.hbs | 1 + .../admin/screened_ip_addresses_controller.rb | 17 ++++++++++++- app/models/screened_ip_address.rb | 25 ++++++++----------- config/locales/client.en.yml | 1 + lib/ip_addr.rb | 19 ++++++++++++++ .../screened_ip_addresses_controller_spec.rb | 14 ++++++++--- 8 files changed, 65 insertions(+), 23 deletions(-) diff --git a/app/assets/javascripts/admin/controllers/admin-logs-screened-ip-addresses.js.es6 b/app/assets/javascripts/admin/controllers/admin-logs-screened-ip-addresses.js.es6 index 0427fe0fb90..a602973409a 100644 --- a/app/assets/javascripts/admin/controllers/admin-logs-screened-ip-addresses.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-logs-screened-ip-addresses.js.es6 @@ -3,15 +3,16 @@ import { outputExportResult } from 'discourse/lib/export-result'; export default Ember.ArrayController.extend(Discourse.Presence, { loading: false, itemController: 'admin-log-screened-ip-address', + filter: null, - show: function() { + show: Discourse.debounce(function() { var self = this; self.set('loading', true); - Discourse.ScreenedIpAddress.findAll().then(function(result) { + Discourse.ScreenedIpAddress.findAll(this.get("filter")).then(function(result) { self.set('model', result); self.set('loading', false); }); - }, + }, 250).observes("filter"), actions: { recordAdded: function(arg) { diff --git a/app/assets/javascripts/admin/models/screened_ip_address.js b/app/assets/javascripts/admin/models/screened_ip_address.js index 22ff7d91539..4aafe4df9ce 100644 --- a/app/assets/javascripts/admin/models/screened_ip_address.js +++ b/app/assets/javascripts/admin/models/screened_ip_address.js @@ -45,8 +45,8 @@ Discourse.ScreenedIpAddress = Discourse.Model.extend({ }); Discourse.ScreenedIpAddress.reopenClass({ - findAll: function() { - return Discourse.ajax("/admin/logs/screened_ip_addresses.json").then(function(screened_ips) { + findAll: function(filter) { + return Discourse.ajax("/admin/logs/screened_ip_addresses.json", { data: { filter: filter } }).then(function(screened_ips) { return screened_ips.map(function(b) { return Discourse.ScreenedIpAddress.create(b); }); diff --git a/app/assets/javascripts/admin/templates/logs/screened_ip_addresses.hbs b/app/assets/javascripts/admin/templates/logs/screened_ip_addresses.hbs index c1b27eb88fb..27fa4237110 100644 --- a/app/assets/javascripts/admin/templates/logs/screened_ip_addresses.hbs +++ b/app/assets/javascripts/admin/templates/logs/screened_ip_addresses.hbs @@ -1,5 +1,6 @@

{{i18n 'admin.logs.screened_ips.description'}}

+ {{text-field value=filter class="ip-address-input" placeholderKey="admin.logs.screened_ips.form.filter" autocorrect="off" autocapitalize="off"}}
diff --git a/app/controllers/admin/screened_ip_addresses_controller.rb b/app/controllers/admin/screened_ip_addresses_controller.rb index 079e674fb53..95281a55abe 100644 --- a/app/controllers/admin/screened_ip_addresses_controller.rb +++ b/app/controllers/admin/screened_ip_addresses_controller.rb @@ -1,9 +1,24 @@ +require_dependency 'ip_addr' + class Admin::ScreenedIpAddressesController < Admin::AdminController before_filter :fetch_screened_ip_address, only: [:update, :destroy] def index - screened_ip_addresses = ScreenedIpAddress.limit(200).order('match_count desc').to_a + filter = params[:filter] + filter = IPAddr.handle_wildcards(filter) + + screened_ip_addresses = ScreenedIpAddress + screened_ip_addresses = screened_ip_addresses.where("cidr '#{filter}' >>= ip_address") if filter.present? + screened_ip_addresses = screened_ip_addresses.limit(200).order('match_count desc') + + begin + screened_ip_addresses = screened_ip_addresses.to_a + rescue ActiveRecord::StatementInvalid + # postgresql throws a PG::InvalidTextRepresentation exception when filter isn't a valid cidr expression + screened_ip_addresses = [] + end + render_serialized(screened_ip_addresses, ScreenedIpAddressSerializer) end diff --git a/app/models/screened_ip_address.rb b/app/models/screened_ip_address.rb index d5547660270..d25540a8535 100644 --- a/app/models/screened_ip_address.rb +++ b/app/models/screened_ip_address.rb @@ -24,23 +24,20 @@ class ScreenedIpAddress < ActiveRecord::Base return end - return write_attribute(:ip_address, val) if val.is_a?(IPAddr) - - num_wildcards = val.count('*') - if num_wildcards == 0 + if val.is_a?(IPAddr) write_attribute(:ip_address, val) - else - v = val.gsub(/\/.*/, '') # strip ranges like "/16" from the end if present - if v[v.index('*')..-1] =~ /[^\.\*]/ - self.errors.add(:ip_address, :invalid) - return - end - parts = v.split('.') - (4 - parts.size).times { parts << '*' } # support strings like 192.* - v = parts.join('.') - write_attribute(:ip_address, "#{v.gsub('*', '0')}/#{32 - (v.count('*') * 8)}") + return end + v = IPAddr.handle_wildcards(val) + + if v.nil? + self.errors.add(:ip_address, :invalid) + return + end + + write_attribute(:ip_address, v) + # this gets even messier, Ruby 1.9.2 raised a different exception to Ruby 2.0.0 # handle both exceptions rescue ArgumentError, IPAddr::InvalidAddressError diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 3d1daeb24e6..b4b708d795d 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -1928,6 +1928,7 @@ en: label: "New:" ip_address: "IP address" add: "Add" + filter: "Search" roll_up: text: "Roll up" title: "Creates new subnet ban entries if there are at least 'min_ban_entries_for_roll_up' entries." diff --git a/lib/ip_addr.rb b/lib/ip_addr.rb index c8afcde4807..c80501c3bb0 100644 --- a/lib/ip_addr.rb +++ b/lib/ip_addr.rb @@ -1,5 +1,24 @@ class IPAddr + def self.handle_wildcards(val) + return if val.blank? + + num_wildcards = val.count('*') + + return val if num_wildcards == 0 + + # strip ranges like "/16" from the end if present + v = val.gsub(/\/.*/, '') + + return if v[v.index('*')..-1] =~ /[^\.\*]/ + + parts = v.split('.') + (4 - parts.size).times { parts << '*' } # support strings like 192.* + v = parts.join('.') + + "#{v.gsub('*', '0')}/#{32 - (v.count('*') * 8)}" + end + def to_cidr_s if @addr mask = @mask_addr.to_s(2).count('1') diff --git a/spec/controllers/admin/screened_ip_addresses_controller_spec.rb b/spec/controllers/admin/screened_ip_addresses_controller_spec.rb index dd106862db8..e814c7abf12 100644 --- a/spec/controllers/admin/screened_ip_addresses_controller_spec.rb +++ b/spec/controllers/admin/screened_ip_addresses_controller_spec.rb @@ -10,10 +10,18 @@ describe Admin::ScreenedIpAddressesController do describe 'index' do - it 'returns JSON' do - xhr :get, :index + it 'filters screened ip addresses' do + Fabricate(:screened_ip_address, ip_address: "1.2.3.4") + Fabricate(:screened_ip_address, ip_address: "1.2.3.5") + Fabricate(:screened_ip_address, ip_address: "1.2.3.6") + Fabricate(:screened_ip_address, ip_address: "4.5.6.7") + + xhr :get, :index, filter: "4.*" + expect(response).to be_success - expect(JSON.parse(response.body)).to be_a(Array) + + result = JSON.parse(response.body) + expect(result.length).to eq(1) end end