diff --git a/util/config/validator.py b/util/config/validator.py index a492be3d6..8d7c36374 100644 --- a/util/config/validator.py +++ b/util/config/validator.py @@ -1,7 +1,5 @@ import logging -from hashlib import sha1 - import peewee from flask import Flask @@ -14,7 +12,6 @@ from data.users import LDAP_CERT_FILENAME from oauth.services.github import GithubOAuthService from oauth.services.google import GoogleOAuthService from oauth.services.gitlab import GitLabOAuthService -from util.registry.torrent import torrent_jwt from util.security.ssl import load_certificate, CertInvalidException, KeyInvalidException from util.config.validators.validate_database import DatabaseValidator @@ -26,6 +23,7 @@ from util.config.validators.validate_keystone import KeystoneValidator from util.config.validators.validate_jwt import JWTAuthValidator from util.config.validators.validate_secscan import SecurityScannerValidator from util.config.validators.validate_signer import SignerValidator +from util.config.validators.validate_torrent import BittorrentValidator logger = logging.getLogger(__name__) @@ -233,47 +231,6 @@ def _validate_ssl(config, user_obj, _): raise ConfigValidationException('SSL private key failed to validate: %s' % kie.message) -def _validate_bittorrent(config, user_obj, _): - """ Validates the configuration for using BitTorrent for downloads. """ - announce_url = config.get('BITTORRENT_ANNOUNCE_URL') - if not announce_url: - raise ConfigValidationException('Missing announce URL') - - # Ensure that the tracker is reachable and accepts requests signed with a registry key. - client = app.config['HTTPCLIENT'] - - params = { - 'info_hash': sha1('somedata').digest(), - 'peer_id': '-QUAY00-6wfG2wk6wWLc', - 'uploaded': 0, - 'downloaded': 0, - 'left': 0, - 'numwant': 0, - 'port': 80, - } - - encoded_jwt = torrent_jwt(params) - params['jwt'] = encoded_jwt - - resp = client.get(announce_url, timeout=5, params=params) - logger.debug('Got tracker response: %s: %s', resp.status_code, resp.text) - - if resp.status_code == 404: - raise ConfigValidationException('Announce path not found; did you forget `/announce`?') - - if resp.status_code == 500: - raise ConfigValidationException('Did not get expected response from Tracker; ' + - 'please check your settings') - - if resp.status_code == 200: - if 'invalid jwt' in resp.text: - raise ConfigValidationException('Could not authorize to Tracker; is your Tracker ' + - 'properly configured?') - - if 'failure reason' in resp.text: - raise ConfigValidationException('Could not validate signed announce request: ' + resp.text) - - VALIDATORS = { DatabaseValidator.name: DatabaseValidator.validate, RedisValidator.name: RedisValidator.validate, @@ -290,5 +247,5 @@ VALIDATORS = { KeystoneValidator.name: KeystoneValidator.validate, SignerValidator.name: SignerValidator.validate, SecurityScannerValidator.name: SecurityScannerValidator.validate, - 'bittorrent': _validate_bittorrent, + BittorrentValidator.name: BittorrentValidator.validate, } diff --git a/util/config/validators/test/test_validate_torrent.py b/util/config/validators/test/test_validate_torrent.py new file mode 100644 index 000000000..69d29232d --- /dev/null +++ b/util/config/validators/test/test_validate_torrent.py @@ -0,0 +1,28 @@ +import pytest + +from httmock import urlmatch, HTTMock + +from util.config.validators import ConfigValidationException +from util.config.validators.validate_torrent import BittorrentValidator + +@pytest.mark.parametrize('unvalidated_config,expected', [ + ({}, ConfigValidationException), + ({'BITTORRENT_ANNOUNCE_URL': 'http://faketorrent/announce'}, None), +]) +def test_validate_torrent(unvalidated_config,expected): + announcer_hit = [False] + + @urlmatch(netloc=r'faketorrent', path='/announce') + def handler(url, request): + announcer_hit[0] = True + return {'status_code': 200, 'content': ''} + + with HTTMock(handler): + validator = BittorrentValidator() + if expected is not None: + with pytest.raises(expected): + validator.validate(unvalidated_config, None, None) + assert not announcer_hit[0] + else: + validator.validate(unvalidated_config, None, None) + assert announcer_hit[0] diff --git a/util/config/validators/validate_torrent.py b/util/config/validators/validate_torrent.py new file mode 100644 index 000000000..2cfc376b6 --- /dev/null +++ b/util/config/validators/validate_torrent.py @@ -0,0 +1,53 @@ +import logging + +from hashlib import sha1 + +from app import app +from util.config.validators import BaseValidator, ConfigValidationException +from util.registry.torrent import torrent_jwt + +logger = logging.getLogger(__name__) + +class BittorrentValidator(BaseValidator): + name = "bittorrent" + + @classmethod + def validate(cls, config, user, user_password): + """ Validates the configuration for using BitTorrent for downloads. """ + announce_url = config.get('BITTORRENT_ANNOUNCE_URL') + if not announce_url: + raise ConfigValidationException('Missing announce URL') + + # Ensure that the tracker is reachable and accepts requests signed with a registry key. + client = app.config['HTTPCLIENT'] + + params = { + 'info_hash': sha1('somedata').digest(), + 'peer_id': '-QUAY00-6wfG2wk6wWLc', + 'uploaded': 0, + 'downloaded': 0, + 'left': 0, + 'numwant': 0, + 'port': 80, + } + + encoded_jwt = torrent_jwt(params) + params['jwt'] = encoded_jwt + + resp = client.get(announce_url, timeout=5, params=params) + logger.debug('Got tracker response: %s: %s', resp.status_code, resp.text) + + if resp.status_code == 404: + raise ConfigValidationException('Announce path not found; did you forget `/announce`?') + + if resp.status_code == 500: + raise ConfigValidationException('Did not get expected response from Tracker; ' + + 'please check your settings') + + if resp.status_code == 200: + if 'invalid jwt' in resp.text: + raise ConfigValidationException('Could not authorize to Tracker; is your Tracker ' + + 'properly configured?') + + if 'failure reason' in resp.text: + raise ConfigValidationException('Could not validate signed announce request: ' + resp.text)