From 6df7f60e4af0b0d967d251660e9973a641132b42 Mon Sep 17 00:00:00 2001 From: Joseph Schorr Date: Wed, 14 Oct 2015 12:18:04 -0400 Subject: [PATCH] Make sure to filter wildcard queries Fixes #640 --- data/model/_basequery.py | 14 +++++++++++++- data/model/repository.py | 8 ++++---- data/model/team.py | 10 ++++++---- data/model/user.py | 18 ++++++++++-------- 4 files changed, 33 insertions(+), 17 deletions(-) diff --git a/data/model/_basequery.py b/data/model/_basequery.py index 131f860e7..d7ef40626 100644 --- a/data/model/_basequery.py +++ b/data/model/_basequery.py @@ -1,10 +1,22 @@ -from peewee import JOIN_LEFT_OUTER +from peewee import JOIN_LEFT_OUTER, Clause, SQL from cachetools import lru_cache from data.database import (Repository, User, Team, TeamMember, RepositoryPermission, TeamRole, Namespace, Visibility, db_for_update) +def prefix_search(field, prefix_query): + """ Returns the wildcard match for searching for the given prefix query. """ + # Escape the known wildcard characters. + prefix_query = (prefix_query + .replace('!', '!!') + .replace('%', '!%') + .replace('_', '!_') + .replace('[', '![')) + + return field ** Clause(prefix_query + '%', SQL("ESCAPE '!'")) + + def get_existing_repository(namespace_name, repository_name, for_update=False): query = (Repository .select(Repository, Namespace) diff --git a/data/model/repository.py b/data/model/repository.py index 4a732d346..af2a1d6d1 100644 --- a/data/model/repository.py +++ b/data/model/repository.py @@ -332,11 +332,11 @@ def get_sorted_matching_repositories(prefix, only_public, checker, limit=10): # For performance reasons, we conduct the repo name and repo namespace searches on their # own. This also affords us the ability to give higher precedence to repository names matching # over namespaces, which is semantically correct. - get_search_results(Repository.name ** (prefix + '%'), with_count=True) - get_search_results(Repository.name ** (prefix + '%'), with_count=False) + get_search_results(_basequery.prefix_search(Repository.name, prefix), with_count=True) + get_search_results(_basequery.prefix_search(Repository.name, prefix), with_count=False) - get_search_results(Namespace.username ** (prefix + '%'), with_count=True) - get_search_results(Namespace.username ** (prefix + '%'), with_count=False) + get_search_results(_basequery.prefix_search(Namespace.username, prefix), with_count=True) + get_search_results(_basequery.prefix_search(Namespace.username, prefix), with_count=False) return results diff --git a/data/model/team.py b/data/model/team.py index 532d55d3a..c7d810b80 100644 --- a/data/model/team.py +++ b/data/model/team.py @@ -137,12 +137,13 @@ def add_or_invite_to_team(inviter, team, user_obj=None, email=None, requires_inv def get_matching_user_teams(team_prefix, user_obj, limit=10): + team_prefix_search = _basequery.prefix_search(Team.name, team_prefix) query = (Team .select() .join(User) .switch(Team) .join(TeamMember) - .where(TeamMember.user == user_obj, Team.name ** (team_prefix + '%')) + .where(TeamMember.user == user_obj, team_prefix_search) .distinct(Team.id) .limit(limit)) @@ -162,6 +163,7 @@ def get_organization_team(orgname, teamname): def get_matching_admined_teams(team_prefix, user_obj, limit=10): + team_prefix_search = _basequery.prefix_search(Team.name, team_prefix) admined_orgs = (_basequery.get_user_organizations(user_obj.username) .switch(Team) .join(TeamRole) @@ -172,7 +174,7 @@ def get_matching_admined_teams(team_prefix, user_obj, limit=10): .join(User) .switch(Team) .join(TeamMember) - .where(Team.name ** (team_prefix + '%'), Team.organization << (admined_orgs)) + .where(team_prefix_search, Team.organization << (admined_orgs)) .distinct(Team.id) .limit(limit)) @@ -180,8 +182,8 @@ def get_matching_admined_teams(team_prefix, user_obj, limit=10): def get_matching_teams(team_prefix, organization): - query = Team.select().where(Team.name ** (team_prefix + '%'), - Team.organization == organization) + team_prefix_search = _basequery.prefix_search(Team.name, team_prefix) + query = Team.select().where(team_prefix_search, Team.organization == organization) return query.limit(10) diff --git a/data/model/user.py b/data/model/user.py index 1a7709ec7..ab1968040 100644 --- a/data/model/user.py +++ b/data/model/user.py @@ -203,9 +203,11 @@ def get_matching_robots(name_prefix, username, limit=10): prefix_checks = False for org in admined_orgs: - prefix_checks = prefix_checks | (User.username ** (org.username + '+' + name_prefix + '%')) + org_search = _basequery.prefix_search(User.username, org.username + '+' + name_prefix) + prefix_checks = prefix_checks | org_search - prefix_checks = prefix_checks | (User.username ** (username + '+' + name_prefix + '%')) + user_search = _basequery.prefix_search(User.username, username + '+' + name_prefix) + prefix_checks = prefix_checks | user_search return User.select().where(prefix_checks).limit(limit) @@ -493,26 +495,26 @@ def get_user_or_org_by_customer_id(customer_id): def get_matching_user_namespaces(namespace_prefix, username, limit=10): + namespace_search = _basequery.prefix_search(Namespace.username, namespace_prefix) base_query = (Namespace .select() .distinct() .limit(limit) .join(Repository, on=(Repository.namespace_user == Namespace.id)) .join(RepositoryPermission, JOIN_LEFT_OUTER) - .where(Namespace.username ** (namespace_prefix + '%'))) + .where(namespace_search)) return _basequery.filter_to_repos_for_user(base_query, username) def get_matching_users(username_prefix, robot_namespace=None, organization=None): - direct_user_query = (User.username ** (username_prefix + '%') & - (User.organization == False) & (User.robot == False)) + user_search = _basequery.prefix_search(User.username, username_prefix) + direct_user_query = (user_search & (User.organization == False) & (User.robot == False)) if robot_namespace: robot_prefix = format_robot_username(robot_namespace, username_prefix) - direct_user_query = (direct_user_query | - (User.username ** (robot_prefix + '%') & - (User.robot == True))) + robot_search = _basequery.prefix_search(User.username, robot_prefix) + direct_user_query = (direct_user_query | (robot_search & (User.robot == True))) query = (User .select(User.username, User.email, User.robot)