mirror of
https://github.com/discourse/discourse.git
synced 2024-11-24 06:15:28 +08:00
142 lines
4.3 KiB
Ruby
142 lines
4.3 KiB
Ruby
require_dependency 'ip_addr'
|
|
|
|
class Admin::ScreenedIpAddressesController < Admin::AdminController
|
|
|
|
before_filter :fetch_screened_ip_address, only: [:update, :destroy]
|
|
|
|
def index
|
|
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
|
|
|
|
def create
|
|
screened_ip_address = ScreenedIpAddress.new(allowed_params)
|
|
if screened_ip_address.save
|
|
render_serialized(screened_ip_address, ScreenedIpAddressSerializer)
|
|
else
|
|
render_json_error(screened_ip_address)
|
|
end
|
|
end
|
|
|
|
def update
|
|
if @screened_ip_address.update_attributes(allowed_params)
|
|
render json: success_json
|
|
else
|
|
render_json_error(@screened_ip_address)
|
|
end
|
|
end
|
|
|
|
def destroy
|
|
@screened_ip_address.destroy
|
|
render json: success_json
|
|
end
|
|
|
|
def star_subnets_query
|
|
@star_subnets_query ||= <<-SQL
|
|
SELECT network(inet(host(ip_address) || '/24')) AS ip_range
|
|
FROM screened_ip_addresses
|
|
WHERE action_type = #{ScreenedIpAddress.actions[:block]}
|
|
AND family(ip_address) = 4
|
|
AND masklen(ip_address) = 32
|
|
GROUP BY ip_range
|
|
HAVING COUNT(*) >= :min_count
|
|
SQL
|
|
end
|
|
|
|
def star_star_subnets_query
|
|
@star_star_subnets_query ||= <<-SQL
|
|
WITH weighted_subnets AS (
|
|
SELECT network(inet(host(ip_address) || '/16')) AS ip_range,
|
|
CASE masklen(ip_address)
|
|
WHEN 32 THEN 1
|
|
WHEN 24 THEN :roll_up_weight
|
|
ELSE 0
|
|
END AS weight
|
|
FROM screened_ip_addresses
|
|
WHERE action_type = #{ScreenedIpAddress.actions[:block]}
|
|
AND family(ip_address) = 4
|
|
)
|
|
SELECT ip_range
|
|
FROM weighted_subnets
|
|
GROUP BY ip_range
|
|
HAVING SUM(weight) >= :min_count
|
|
SQL
|
|
end
|
|
|
|
def star_subnets
|
|
min_count = SiteSetting.min_ban_entries_for_roll_up
|
|
ScreenedIpAddress.exec_sql(star_subnets_query, min_count: min_count).values.flatten
|
|
end
|
|
|
|
def star_star_subnets
|
|
weight = SiteSetting.min_ban_entries_for_roll_up
|
|
ScreenedIpAddress.exec_sql(star_star_subnets_query, min_count: 10, roll_up_weight: weight).values.flatten
|
|
end
|
|
|
|
def roll_up
|
|
# 1 - retrieve all subnets that needs roll up
|
|
subnets = [star_subnets, star_star_subnets].flatten
|
|
|
|
# 2 - log the call
|
|
StaffActionLogger.new(current_user).log_roll_up(subnets) unless subnets.blank?
|
|
|
|
subnets.each do |subnet|
|
|
# 3 - create subnet if not already exists
|
|
ScreenedIpAddress.new(ip_address: subnet).save unless ScreenedIpAddress.where(ip_address: subnet).first
|
|
|
|
# 4 - 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 = #{ScreenedIpAddress.actions[:block]}
|
|
AND family(ip_address) = 4
|
|
AND ip_address << :ip_address
|
|
) s
|
|
WHERE ip_address = :ip_address
|
|
SQL
|
|
|
|
ScreenedIpAddress.exec_sql(sql, ip_address: subnet)
|
|
|
|
# 5 - remove old matches
|
|
ScreenedIpAddress.where(action_type: ScreenedIpAddress.actions[:block])
|
|
.where("family(ip_address) = 4")
|
|
.where("ip_address << ?", subnet)
|
|
.delete_all
|
|
end
|
|
|
|
render json: success_json.merge!({ subnets: subnets })
|
|
end
|
|
|
|
private
|
|
|
|
def allowed_params
|
|
params.require(:ip_address)
|
|
params.permit(:ip_address, :action_name)
|
|
end
|
|
|
|
def fetch_screened_ip_address
|
|
@screened_ip_address = ScreenedIpAddress.find(params[:id])
|
|
end
|
|
|
|
end
|