gitweb: Validate repository name also in actions script

This prevents writing to an arbitrary directory if running actions script
as a root user.

- Included tests for invalid names

Signed-off-by: Veiko Aasa <veiko17@disroot.org>
[sunil@medhas.org Parametrize the test case]
Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org>
Reviewed-by: Sunil Mohan Adapa <sunil@medhas.org>
This commit is contained in:
Veiko Aasa 2019-10-28 18:44:26 +03:00 committed by Sunil Mohan Adapa
parent 0b2d1265cb
commit ba9869c030
No known key found for this signature in database
GPG Key ID: 43EA1CFF0AA7C5F2
3 changed files with 39 additions and 5 deletions

View File

@ -27,6 +27,7 @@ import shutil
import subprocess
from plinth import action_utils
from plinth.modules.gitweb.forms import validate_repository
from plinth.modules.gitweb.manifest import GIT_REPO_PATH
@ -168,6 +169,8 @@ def _set_access_status(repo, status):
def subcommand_rename_repo(arguments):
"""Rename a repository."""
validate_repository(arguments.oldname)
validate_repository(arguments.newname)
oldpath = os.path.join(GIT_REPO_PATH, arguments.oldname + '.git')
newpath = os.path.join(GIT_REPO_PATH, arguments.newname + '.git')
os.rename(oldpath, newpath)
@ -175,21 +178,25 @@ def subcommand_rename_repo(arguments):
def subcommand_set_repo_description(arguments):
"""Set description of the repository."""
validate_repository(arguments.name)
_set_repo_description(arguments.name, arguments.description)
def subcommand_set_repo_owner(arguments):
"""Set repository's owner name."""
validate_repository(arguments.name)
_set_repo_owner(arguments.name, arguments.owner)
def subcommand_set_repo_access(arguments):
"""Set repository's access status."""
validate_repository(arguments.name)
_set_access_status(arguments.name, arguments.access)
def subcommand_repo_info(arguments):
"""Get information about repository."""
validate_repository(arguments.name)
repo_path = os.path.join(GIT_REPO_PATH, arguments.name + '.git')
if not os.path.exists(repo_path):
raise RuntimeError('Repository not found')
@ -203,6 +210,7 @@ def subcommand_repo_info(arguments):
def subcommand_create_repo(arguments):
"""Create a new git repository."""
validate_repository(arguments.name)
os.chdir(GIT_REPO_PATH)
repo_name = arguments.name + '.git'
subprocess.check_call(['git', 'init', '--bare', repo_name])
@ -216,6 +224,7 @@ def subcommand_create_repo(arguments):
def subcommand_delete_repo(arguments):
"""Delete a git repository."""
validate_repository(arguments.name)
repo_path = os.path.join(GIT_REPO_PATH, arguments.name + '.git')
shutil.rmtree(repo_path)

View File

@ -18,6 +18,8 @@
Django form for configuring Gitweb.
"""
import re
from django import forms
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _
@ -25,13 +27,26 @@ from django.utils.translation import ugettext_lazy as _
from plinth.modules import gitweb
def validate_repository(name):
"""Validate a Git repository name."""
if not re.match(r'^[a-zA-Z0-9-._]+$', name):
raise ValidationError(_('Invalid repository name.'))
if name.startswith(('-', '.')):
raise ValidationError(_('Invalid repository name.'))
if name.endswith('.git.git'):
raise ValidationError(_('Invalid repository name.'))
class EditRepoForm(forms.Form):
"""Form to create and edit a new repository."""
name = forms.RegexField(
name = forms.CharField(
label=_('Name of the repository'),
strip=True,
regex=r'^[a-zA-Z0-9-._]+$',
validators=[validate_repository],
help_text=_(
'An alpha-numeric string that uniquely identifies a repository.'),
)
@ -62,9 +77,6 @@ class EditRepoForm(forms.Form):
if name.endswith('.git'):
name = name[:-4]
if (not name) or name.startswith(('-', '.')):
raise ValidationError(_('Invalid repository name.'))
for repo in gitweb.app.get_repo_list():
if name == repo['name']:
raise ValidationError(

View File

@ -24,6 +24,7 @@ import pathlib
from unittest.mock import patch
import pytest
from django.forms import ValidationError
def _action_file():
@ -91,3 +92,15 @@ def test_actions(call_action):
call_action(['delete-repo', '--name', repo_renamed])
with pytest.raises(RuntimeError, match='Repository not found'):
call_action(['repo-info', '--name', repo_renamed])
@pytest.mark.parametrize(
'name',
['.Test-repo', 'Test-repo.git.git', '/root/Test-repo', 'Test-repö'])
def test_action_create_repo_with_invalid_names(call_action, name):
"""Test that creating repository with invalid names fails."""
with pytest.raises(ValidationError):
call_action([
'create-repo', '--name', name, '--description', '', '--owner', '',
'--keep-ownership'
])