Проверка, является ли строка префиксом любого шаблона URL - PullRequest
0 голосов
/ 31 мая 2018

Невидимый или нет, мой сайт Django назначает каждому пользователю страницу в корне, например, /rgov.

Я использую белый список набора символов, поэтому создание index.html или что-то нечистое должно быть предотвращено.Моя конфигурация URL также маршрутизирует пользовательские страницы в последнюю очередь, поэтому не должно быть возможности перехватить /admin или что-либо еще, зарегистрировав соответствующее имя.

Однако я бы хотел запретить пользователям регистрировать admin,поскольку их страница будет разбита.

( Аналогичный вопрос , который не имеет идеального решения, как описано в следующей части.)


Вот мойпопытка:

def is_reserved(username):
  r = urls.resolvers.get_resolver('mysite.systemurls')
  hit = False
  for path in ('/{}', '/{}/'):
    try:
      r.resolve(path.format(username))
      hit = True
      break
    except urls.exceptions.Resolver404:
      continue
  return hit

Здесь модуль mysite.systemurls определяет каждый шаблон URL, кроме страниц пользователя.

Это предотвращает выбор имени пользователя admin, поскольку для этого маршрута определен маршрут/admin/.Но это не мешает api, потому что, пока существует /api/foo/bar, нет маршрута для /api/.

Есть ли способ проверить, существует ли маршрут с суффиксом /api/ (например)?Поскольку шаблоны URL являются регулярными выражениями, возможно, это не так просто, но в теоретическом смысле это должно быть возможно.

1 Ответ

0 голосов
/ 31 мая 2018

Вот мое неумелое решение, простите за бельмо на глазу.Я реализовал проверку, используя систему проверок системы Django.Проверка собирает все шаблоны URL, используемые приложением, а затем извлекает первый компонент пути из каждого.Затем он проверяет, что ни один из этих компонентов первого пути

Если у вас есть re_path в шаблонах URL, которые нарушают сделанные предположения, это не будет работать.

import re

from django import urls
from django.core.checks import register, Error, Tags, Warning

from . import usernames


@register(Tags.urls, Tags.security)
def check_scary_available_usernames(app_configs=None, **kwargs):
  '''
  Checks that there are no URL patterns /x/y where /x itself is not a pattern.
  In this case, /x might be available for user registration, which would be bad.
  '''
  errors, prefixes = [], set()
  r = urls.resolvers.get_resolver('mysite.systemurls')
  descend_into_resolver(r, [], errors, prefixes)

  # Check to make sure none of these usernames is taken or available
  for prefix in prefixes:
    if not prefix:
      continue
    if not usernames.is_reserved(prefix):
      errors.append(Warning(
        'There is no restriction on registering the forbidden username {}, '
        'which would conflict with a URL in use by the system.'.format(prefix)
      ))
    if usernames.user_exists(prefix):
      errors.append(Warning(
        'A user has the forbidden username {}, which conflicts with a URL in '
        'use by the system.'.format(prefix)
      ))
  return errors


def descend_into_resolver(resolver, chain, errors, prefixes):
  for up in resolver.url_patterns:
    regex = up.pattern.regex.pattern
    if isinstance(up, urls.resolvers.URLResolver):
      descend_into_resolver(up, chain + [regex], errors, prefixes)
    elif isinstance(up, urls.resolvers.URLPattern):
      collect_pattern_prefix(chain + [regex], errors, prefixes)
    else:
      errors.append(Warning(
        'Resolver has unexpected URL pattern: {}'.format(repr(up))
      ))


def collect_pattern_prefix(patterns, errors, prefixes):
  # Remember, we are matching against a regular expression pattern! We are not
  # taking a robust approach; if it fails, this could report spurious warnings.
  uberpattern = r''
  for i, pattern in enumerate(patterns):
    if i != 0:
      pattern = pattern.lstrip('^')
    if i != len(patterns) - 1:
      pattern = pattern.rstrip('$')
    uberpattern += pattern
  uberpattern = uberpattern.replace('\\/', '/')

  m = re.match(r'^\^?([^/$]*)', uberpattern)
  if m is None:
    errors.append(Warning(
      'Could not determine first component of URL pattern '
      '{}'.format(uberpattern)
    ))
  else:
    prefixes.add(m.group(1))
...