PK t[CR;% % iprestrict/__init__.pyfrom restrictor import IPRestrictor
PK H1H>T T iprestrict/admin.pyfrom iprestrict import models
from django.contrib import admin
from django import forms
import ip_utils as ipu
class RuleAdmin(admin.ModelAdmin):
model = models.Rule
exclude = ('rank',)
list_display = ('url_pattern', 'ip_group', 'is_allowed', 'move_up_url', 'move_down_url')
class IPRangeForm(forms.ModelForm):
class Meta:
model = models.IPRange
def clean_cidr_prefix_length(self):
cidr = self.cleaned_data['cidr_prefix_length']
if cidr:
if not (1 <= cidr <= 31):
raise forms.ValidationError("Must be a number between 1 and 31")
return cidr
def clean(self):
cleaned_data = super(IPRangeForm, self).clean()
first_ip = cleaned_data.get('first_ip')
if first_ip is None:
# first_ip is Mandatory, so just let the default validator catch this
return cleaned_data
last_ip = cleaned_data['last_ip']
cidr = cleaned_data['cidr_prefix_length']
if last_ip and cidr:
raise forms.ValidationError("Don't specify the Last IP if you specified a CIDR prefix length")
if last_ip:
if ipu.get_version(first_ip) != ipu.get_version(last_ip):
raise forms.ValidationError("Last IP should be the same type as First IP (%s)" % ipu.get_version(first_ip))
if ipu.get_version(last_ip) != 'ipv6':
# Ignore rest of validation for ipv6, support isn't there yet
if ipu.to_number(first_ip) > ipu.to_number(last_ip):
raise forms.ValidationError("Last IP should be greater than First IP")
if cidr:
# With CIDR the starting address could be different than the one
# the user specified. Making sure it is set to the first ip in the
# subnet.
start, end = ipu.cidr_to_range(first_ip, cidr)
cleaned_data['first_ip'] = ipu.to_ip(start)
return cleaned_data
class IPRangeInline(admin.TabularInline):
model = models.IPRange
form = IPRangeForm
fields = ['first_ip', 'cidr_prefix_length', 'last_ip', 'ip_type']
readonly_fields = ['ip_type']
extra = 2
class IPGroupAdmin(admin.ModelAdmin):
model = models.IPGroup
inlines = [IPRangeInline]
admin.site.register(models.Rule, RuleAdmin)
admin.site.register(models.IPGroup, IPGroupAdmin)
PK H1HWw iprestrict/decorators.pyfrom functools import wraps
from django.utils.translation import ugettext as _
from django.contrib.admin.forms import AdminAuthenticationForm
from django.contrib.auth.views import login
from django.contrib.auth import REDIRECT_FIELD_NAME
from django.http import HttpResponseForbidden
# Copied from django staff_member_required
# Why isn't this provided by Django?
def superuser_required(view_func):
"""
Decorator for views that checks that the user is logged in and is a staff
member, displaying the login page if necessary.
"""
@wraps(view_func)
def _checklogin(request, *args, **kwargs):
if request.user.is_active and request.user.is_superuser:
# The user is valid. Continue to the admin page.
return view_func(request, *args, **kwargs)
if request.user.is_authenticated():
return HttpResponseForbidden('Forbidden!')
assert hasattr(request, 'session'), "The Django admin requires session middleware to be installed. Edit your MIDDLEWARE_CLASSES setting to insert 'django.contrib.sessions.middleware.SessionMiddleware'."
defaults = {
'template_name': 'admin/login.html',
'authentication_form': AdminAuthenticationForm,
'extra_context': {
'title': _('Log in'),
'app_path': request.get_full_path(),
REDIRECT_FIELD_NAME: request.get_full_path(),
},
}
return login(request, **defaults)
return _checklogin
PK H1HB6 iprestrict/ip_utils.py
def get_version(ip):
return 'ipv4' if '.' in ip else 'ipv6'
def to_number(ip):
parts= ip.split('.')
parts = [int(p) for p in reversed(parts)]
nr = 0
for i, d in enumerate(parts):
nr += (256 ** i) * d
return nr
def to_ip(number):
mask = int('1' * 8, 2)
parts = []
for i in range(4):
shifted_number = number >> (8 * i)
parts.append(shifted_number & mask)
return '.'.join(map(lambda i: str(i), reversed(parts)))
def cidr_to_range(ip, prefix_length):
ip = to_number(ip)
start_mask = int('1' * prefix_length, 2) << (32 - prefix_length)
end_mask = int('1' * (32 - prefix_length), 2)
start = ip & start_mask
end = start | end_mask
return (start, end)
PK H1HB! ! iprestrict/middleware.pyfrom django.core import exceptions
from django.utils import log
from iprestrict.models import ReloadRulesRequest
from iprestrict import IPRestrictor
from django.conf import settings
logger = log.getLogger(__name__)
class IPRestrictMiddleware(object):
def __init__(self):
self.restrictor = IPRestrictor()
self.trusted_proxies = getattr(settings, 'TRUSTED_PROXIES', tuple())
self.dont_reload_rules = getattr(settings, 'DONT_RELOAD_RULES', False)
def process_request(self, request):
if not self.dont_reload_rules:
self.reload_rules_if_needed()
url = request.path_info
client_ip = self.extract_client_ip(request)
if self.restrictor.is_restricted(url, client_ip):
logger.info("Denying access of %s to %s" % (url, client_ip))
raise exceptions.PermissionDenied
def extract_client_ip(self, request):
client_ip = request.META['REMOTE_ADDR']
forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
if forwarded_for is not None:
forwarded_for = [ip.strip() for ip in forwarded_for.split(',')]
closest_proxy = client_ip
client_ip = forwarded_for.pop(0)
proxies = [closest_proxy] + forwarded_for
for proxy in proxies:
if proxy not in self.trusted_proxies:
logger.info("Client IP %s forwarded by untrusted proxy %s"
% (client_ip, proxy))
raise exceptions.PermissionDenied
return client_ip
def reload_rules_if_needed(self):
last_reload_request = ReloadRulesRequest.last_request()
if last_reload_request is not None:
if self.restrictor.last_reload < last_reload_request:
self.restrictor.reload_rules()
PK H1HܗC C iprestrict/models.pyfrom django.core.urlresolvers import reverse
from django.db import models
from datetime import datetime
import re
from iprestrict import ip_utils as ipu
class IPGroup(models.Model):
class Meta:
verbose_name = "IP Group"
name = models.CharField(max_length=100)
description = models.TextField(null=True, blank=True)
def __init__(self, *args, **kwargs):
models.Model.__init__(self, *args, **kwargs)
self.load_ranges()
def load_ranges(self):
self._ranges = { 'ipv4': [], 'ipv6': [] }
for r in self.iprange_set.all():
self._ranges[r.ip_type].append(r)
def ranges(self, ip_type='ipv4'):
return self._ranges[ip_type]
def matches(self, ip):
ip_type = ipu.get_version(ip)
for r in self.ranges(ip_type):
if ip in r:
return True
return False
def ranges_str(self):
return ', '.join([str(r) for r in self.ranges()])
def __unicode__(self):
return self.name
class IPRange(models.Model):
class Meta:
verbose_name = "IP Range"
ip_group = models.ForeignKey(IPGroup)
first_ip = models.GenericIPAddressField()
cidr_prefix_length = models.PositiveSmallIntegerField(null=True, blank=True)
last_ip = models.GenericIPAddressField(null=True, blank=True)
@property
def start(self):
if self.cidr_prefix_length is not None:
start, end = ipu.cidr_to_range(self.first_ip,
self.cidr_prefix_length)
return start
else:
return ipu.to_number(self.first_ip)
@property
def end(self):
if self.last_ip is not None:
return ipu.to_number(self.last_ip)
if self.cidr_prefix_length is not None:
start, end = ipu.cidr_to_range(self.first_ip,
self.cidr_prefix_length)
return end
return self.start
@property
def ip_type(self):
if not self.first_ip:
return ''
return ipu.get_version(self.first_ip)
def __contains__(self, ip):
ip_nr = ipu.to_number(ip)
return self.start <= ip_nr <= self.end
def __unicode__(self):
result = str(self.first_ip)
if self.cidr_prefix_length is not None:
result += '/' + str(self.cidr_prefix_length)
elif self.last_ip is not None:
result += '-' + str(self.last_ip)
return result
class Rule(models.Model):
class Meta:
ordering = ['rank', 'id']
ACTION_CHOICES = (
('A', 'ALLOW'),
('D', 'DENY')
)
url_pattern = models.CharField(max_length=500)
ip_group = models.ForeignKey(IPGroup, default=1)
action = models.CharField(max_length=1, choices=ACTION_CHOICES, default='D')
rank = models.IntegerField(blank=True)
@property
def regex(self):
if not hasattr(self, '_regex'):
self._regex = re.compile(self.url_pattern)
return self._regex
def matches_url(self, url):
if self.url_pattern == 'ALL':
return True
else:
return (self.regex.match(url) is not None)
def matches_ip(self, ip):
return self.ip_group.matches(ip)
def is_restricted(self):
return self.action != 'A'
def is_allowed(self):
return self.action == 'A'
is_allowed.boolean = True
is_allowed.short_description = 'Is allowed?'
def action_str(self):
return 'Allowed' if self.is_allowed() else 'Denied'
def swap_with_rule(self, other):
other.rank, self.rank = self.rank, other.rank
other.save()
self.save()
def move_up(self):
rules_above = Rule.objects.filter(rank__lt = self.rank).order_by('-rank')
if len(rules_above) == 0:
return
self.swap_with_rule(rules_above[0])
def move_up_url(self):
url = reverse('iprestrict.views.move_rule_up', args=[self.pk])
return 'Move Up' % url
move_up_url.allow_tags = True
move_up_url.short_description = 'Move Up'
def move_down_url(self):
url = reverse('iprestrict.views.move_rule_down', args=[self.pk])
return 'Move Down' % url
move_down_url.allow_tags = True
move_down_url.short_description = 'Move Down'
def move_down(self):
rules_below = Rule.objects.filter(rank__gt = self.rank)
if len(rules_below) == 0:
return
self.swap_with_rule(rules_below[0])
def save(self, *args, **kwargs):
if self.rank is None:
max_aggr = Rule.objects.filter(rank__lt = 65000).aggregate(models.Max('rank'))
max_rank = max_aggr.get('rank__max')
if max_rank is None:
max_rank = 0
self.rank = max_rank + 1
super(Rule, self).save(*args, **kwargs)
class ReloadRulesRequest(models.Model):
at = models.DateTimeField(auto_now_add=True)
@classmethod
def request_reload(cls):
rrs = ReloadRulesRequest.objects.all()
if len(rrs) > 0:
obj = rrs[0]
obj.at = datetime.now()
obj.save()
else:
cls.objects.create()
@staticmethod
def last_request():
result = None
rrs = ReloadRulesRequest.objects.all()
if len(rrs) > 0:
result = rrs[0].at
return result
PK H1Hl8 8 iprestrict/restrictor.pyfrom iprestrict import models
from datetime import datetime
class IPRestrictor(object):
def __init__(self):
self.load_rules()
def is_restricted(self, url, ip):
for rule in self.rules:
if rule.matches_url(url) and rule.matches_ip(ip):
return rule.is_restricted()
return False
def load_rules(self):
# We are caching the rules, to avoid DB lookup on each request
self.rules = [r for r in models.Rule.objects.all()]
self.last_reload = datetime.now()
reload_rules = load_rules
PK H1H) ) iprestrict/test_settings.pyfrom os import path
# Django settings for mysite project.
DEBUG = True
TEMPLATE_DEBUG = DEBUG
ADMINS = (
# ('Your Name', 'your_email@example.com'),
)
MANAGERS = ADMINS
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
'NAME': 'db.sqlite3', # Or path to database file if using sqlite3.
'USER': '', # Not used with sqlite3.
'PASSWORD': '', # Not used with sqlite3.
'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
'PORT': '', # Set to empty string for default. Not used with sqlite3.
}
}
# Local time zone for this installation. Choices can be found here:
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
# although not all choices may be available on all operating systems.
# On Unix systems, a value of None will cause Django to use the same
# timezone as the operating system.
# If running in a Windows environment this must be set to the same as your
# system time zone.
TIME_ZONE = 'Australia/Perth'
# Language code for this installation. All choices can be found here:
# http://www.i18nguy.com/unicode/language-identifiers.html
LANGUAGE_CODE = 'en-us'
SITE_ID = 1
# If you set this to False, Django will make some optimizations so as not
# to load the internationalization machinery.
USE_I18N = True
# If you set this to False, Django will not format dates, numbers and
# calendars according to the current locale.
USE_L10N = True
# If you set this to False, Django will not use timezone-aware datetimes.
USE_TZ = False
# Absolute filesystem path to the directory that will hold user-uploaded files.
# Example: "/home/media/media.lawrence.com/media/"
MEDIA_ROOT = ''
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash.
# Examples: "http://media.lawrence.com/media/", "http://example.com/media/"
MEDIA_URL = ''
# Absolute path to the directory static files should be collected to.
# Don't put anything in this directory yourself; store your static files
# in apps' "static/" subdirectories and in STATICFILES_DIRS.
# Example: "/home/media/media.lawrence.com/static/"
STATIC_ROOT = ''
# URL prefix for static files.
# Example: "http://media.lawrence.com/static/"
STATIC_URL = '/static/'
# Additional locations of static files
STATICFILES_DIRS = (
# Put strings here, like "/home/html/static" or "C:/www/django/static".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
)
# List of finder classes that know how to find static files in
# various locations.
STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
# 'django.contrib.staticfiles.finders.DefaultStorageFinder',
)
# Make this unique, and don't share it with anybody.
SECRET_KEY = 're)-uyql-#_jc4q&m99upnmn#epel3#1*lvkh9e^y=r9k0-6z%'
# List of callables that know how to import templates from various sources.
TEMPLATE_LOADERS = (
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
# 'django.template.loaders.eggs.Loader',
)
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'iprestrict.middleware.IPRestrictMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
# Uncomment the next line for simple clickjacking protection:
# 'django.middleware.clickjacking.XFrameOptionsMiddleware',
)
ROOT_URLCONF = 'iprestrict.test_urls'
# Python dotted path to the WSGI application used by Django's runserver.
#WSGI_APPLICATION = 'mysite.wsgi.application'
TEMPLATE_DIRS = (
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
)
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
# Uncomment the next line to enable the admin:
'django.contrib.admin',
# Uncomment the next line to enable admin documentation:
# 'django.contrib.admindocs',
'south',
'templatetag_handlebars',
'iprestrict',
)
# A sample logging configuration. The only tangible logging
# performed by this configuration is to send an email to
# the site admins on every HTTP 500 error when DEBUG=False.
# See http://docs.djangoproject.com/en/dev/topics/logging for
# more details on how to customize your logging configuration.
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'simple': {
'format': '%(levelname)s %(message)s'
},
},
'filters': {
'require_debug_false': {
'()': 'django.utils.log.RequireDebugFalse'
}
},
'handlers': {
'mail_admins': {
'level': 'ERROR',
'filters': ['require_debug_false'],
'class': 'django.utils.log.AdminEmailHandler'
},
'console': {
'level':'DEBUG',
'class':'logging.StreamHandler',
'formatter': 'simple'
},
},
'loggers': {
'django.request': {
'handlers': ['mail_admins'],
'level': 'ERROR',
'propagate': True,
},
'iprestrict': {
'handlers': ['console'],
'level': 'DEBUG',
'propagate': True,
}
}
}
TEST_RUNNER = 'discover_runner.DiscoverRunner'
PK H1HU ! iprestrict/test_settings_1_3_1.pyfrom os import path
# Django settings for mysite project.
DEBUG = True
TEMPLATE_DEBUG = DEBUG
ADMINS = (
# ('Your Name', 'your_email@example.com'),
)
MANAGERS = ADMINS
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
'NAME': 'db.sqlite3',
'USER': '', # Not used with sqlite3.
'PASSWORD': '', # Not used with sqlite3.
'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
'PORT': '', # Set to empty string for default. Not used with sqlite3.
}
}
# Local time zone for this installation. Choices can be found here:
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
# although not all choices may be available on all operating systems.
# On Unix systems, a value of None will cause Django to use the same
# timezone as the operating system.
# If running in a Windows environment this must be set to the same as your
# system time zone.
TIME_ZONE = 'Australia/Perth'
# Language code for this installation. All choices can be found here:
# http://www.i18nguy.com/unicode/language-identifiers.html
LANGUAGE_CODE = 'en-us'
SITE_ID = 1
# If you set this to False, Django will make some optimizations so as not
# to load the internationalization machinery.
USE_I18N = True
# If you set this to False, Django will not format dates, numbers and
# calendars according to the current locale
USE_L10N = True
# Absolute filesystem path to the directory that will hold user-uploaded files.
# Example: "/home/media/media.lawrence.com/media/"
MEDIA_ROOT = ''
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash.
# Examples: "http://media.lawrence.com/media/", "http://example.com/media/"
MEDIA_URL = ''
# Absolute path to the directory static files should be collected to.
# Don't put anything in this directory yourself; store your static files
# in apps' "static/" subdirectories and in STATICFILES_DIRS.
# Example: "/home/media/media.lawrence.com/static/"
STATIC_ROOT = ''
# URL prefix for static files.
# Example: "http://media.lawrence.com/static/"
STATIC_URL = '/static/'
# URL prefix for admin static files -- CSS, JavaScript and images.
# Make sure to use a trailing slash.
# Examples: "http://foo.com/static/admin/", "/static/admin/".
ADMIN_MEDIA_PREFIX = '/static/admin/'
# Additional locations of static files
STATICFILES_DIRS = (
# Put strings here, like "/home/html/static" or "C:/www/django/static".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
)
# List of finder classes that know how to find static files in
# various locations.
STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
# 'django.contrib.staticfiles.finders.DefaultStorageFinder',
)
# Make this unique, and don't share it with anybody.
SECRET_KEY = ''
# List of callables that know how to import templates from various sources.
TEMPLATE_LOADERS = (
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
# 'django.template.loaders.eggs.Loader',
)
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'iprestrict.middleware.IPRestrictMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
)
ROOT_URLCONF = 'iprestrict.urls'
TEMPLATE_DIRS = (
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
path.join(path.dirname(path.dirname(__file__)), 'templates')
)
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
# Uncomment the next line to enable the admin:
# 'django.contrib.admin',
# Uncomment the next line to enable admin documentation:
# 'django.contrib.admindocs',
'iprestrict',
)
# A sample logging configuration. The only tangible logging
# performed by this configuration is to send an email to
# the site admins on every HTTP 500 error.
# See http://docs.djangoproject.com/en/dev/topics/logging for
# more details on how to customize your logging configuration.
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'mail_admins': {
'level': 'ERROR',
'class': 'django.utils.log.AdminEmailHandler'
}
},
'loggers': {
'django.request': {
'handlers': ['mail_admins'],
'level': 'ERROR',
'propagate': True,
},
}
}
TEST_RUNNER = 'discover_runner.DiscoverRunner'
PK H1H" iprestrict/test_urls.py# This file is to be used for testing only
from django.conf.urls import patterns, include, url
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('iprestrict.views',
url(r'^iprestrict/$', 'test_rules_page'),
url(r'^iprestrict/move_rule_up/(?P\d+)[/]?$', 'move_rule_up'),
url(r'^iprestrict/move_rule_down/(?P\d+)[/]?$', 'move_rule_down'),
url(r'^iprestrict/reload_rules[/]?$', 'reload_rules'),
url(r'^iprestrict/test_match[/]?$', 'test_match'),
)
urlpatterns += patterns('',
url(r'^admin/', include(admin.site.urls)),
)
urlpatterns += staticfiles_urlpatterns()
PK H1Hi i iprestrict/urls.pyfrom django.conf.urls import patterns, include, url
urlpatterns = patterns('iprestrict.views',
url(r'^$', 'test_rules_page'),
url(r'^move_rule_up/(?P\d+)[/]?$', 'move_rule_up'),
url(r'^move_rule_down/(?P\d+)[/]?$', 'move_rule_down'),
url(r'^reload_rules[/]?$', 'reload_rules'),
url(r'^test_match[/]?$', 'test_match'),
)
PK H1H3 iprestrict/views.pyfrom django.core.urlresolvers import reverse
from django.http import HttpResponse, HttpResponseRedirect
from iprestrict import models
from iprestrict.restrictor import IPRestrictor
from iprestrict.decorators import superuser_required
from django.shortcuts import render_to_response
import json
@superuser_required
def move_rule_up(request, rule_id):
rule = models.Rule.objects.get(pk=rule_id)
rule.move_up()
return HttpResponseRedirect(reverse('admin:iprestrict_rule_changelist'))
@superuser_required
def move_rule_down(request, rule_id):
rule = models.Rule.objects.get(pk=rule_id)
rule.move_down()
return HttpResponseRedirect(reverse('admin:iprestrict_rule_changelist'))
@superuser_required
def reload_rules(request):
models.ReloadRulesRequest.request_reload()
return HttpResponse('ok')
@superuser_required
def test_rules_page(request):
return render_to_response('iprestrict/test_rules.html')
@superuser_required
def test_match(request):
url = request.REQUEST['url']
ip = request.REQUEST['ip']
matching_rule_id, action = find_matching_rule(url, ip)
rules = list_rules(matching_rule_id, url, ip)
if matching_rule_id is None:
result = {
'action': 'Allowed',
'msg': 'No rules matched.',
}
else:
result = {
'action': action,
'msg': 'URL matched Rule highlighted below.'
}
result['rules'] = rules
return HttpResponse(json.dumps(result))
def find_matching_rule(url, ip):
for r in models.Rule.objects.all():
if r.matches_url(url) and r.matches_ip(ip):
return (r.pk, r.action_str())
return (None, None)
def list_rules(matching_rule_id, url, ip):
return [map_rule(r, matching_rule_id, url, ip) for r in models.Rule.objects.all()]
def map_rule(r, matching_rule_id, url, ip):
rule = {
'url_pattern': {
'value': r.url_pattern,
'matchStatus': 'match' if r.matches_url(url) else 'noMatch'
},
'ip_group': {
'name': r.ip_group.name,
'ranges': r.ip_group.ranges_str(),
'matchStatus': 'match' if r.matches_ip(ip) else 'noMatch'
},
'action': r.action_str(),
}
if r.pk == matching_rule_id:
rule['matched'] = True
return rule
PK t[C ! iprestrict/management/__init__.pyPK t[C * iprestrict/management/commands/__init__.pyPK t[CE[' ' - iprestrict/management/commands/importrules.pyfrom django.core.management.base import BaseCommand
from django.core.management import call_command
from iprestrict import models
class Command(BaseCommand):
help = 'Replaces the current rules in the DB with the rules in the given fixture file(s).'
args = "fixture [fixture ...]"
def handle(self, *args, **options):
verbosity = int(options.get('verbosity', '1'))
self.delete_existing_rules()
if verbosity >= 1:
self.stdout.write('Successfully deleted rules\n')
call_command('loaddata', *args,
verbosity=verbosity,
interactive=False)
def delete_existing_rules(self):
models.Rule.objects.all().delete()
models.IPRange.objects.all().delete()
models.IPGroup.objects.all().delete()
PK t[C$ - iprestrict/management/commands/reloadrules.pyfrom django.core.management.base import BaseCommand
from iprestrict import models
class Command(BaseCommand):
help = 'Requests the reload of the ip restriction rules from the DB.'
def handle(self, *args, **options):
verbosity = int(options.get('verbosity', '1'))
models.ReloadRulesRequest.request_reload()
if verbosity >= 1:
self.stdout.write('Successfully requested reload of rules\n')
PK t[C iprestrict/templates/404.htmlPK t[CЄ
/ iprestrict/templates/iprestrict/test_rules.html{% load staticfiles %}
{% load templatetag_handlebars %}
IPRestrict - Test Rules
Test Rules
Enter a URL and an IP address below, then click Test.