Pull out torrent validation into validator class
This commit is contained in:
parent
2944a4e13d
commit
09b3cfd549
3 changed files with 83 additions and 45 deletions
|
@ -1,7 +1,5 @@
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from hashlib import sha1
|
|
||||||
|
|
||||||
import peewee
|
import peewee
|
||||||
|
|
||||||
from flask import Flask
|
from flask import Flask
|
||||||
|
@ -14,7 +12,6 @@ from data.users import LDAP_CERT_FILENAME
|
||||||
from oauth.services.github import GithubOAuthService
|
from oauth.services.github import GithubOAuthService
|
||||||
from oauth.services.google import GoogleOAuthService
|
from oauth.services.google import GoogleOAuthService
|
||||||
from oauth.services.gitlab import GitLabOAuthService
|
from oauth.services.gitlab import GitLabOAuthService
|
||||||
from util.registry.torrent import torrent_jwt
|
|
||||||
from util.security.ssl import load_certificate, CertInvalidException, KeyInvalidException
|
from util.security.ssl import load_certificate, CertInvalidException, KeyInvalidException
|
||||||
|
|
||||||
from util.config.validators.validate_database import DatabaseValidator
|
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_jwt import JWTAuthValidator
|
||||||
from util.config.validators.validate_secscan import SecurityScannerValidator
|
from util.config.validators.validate_secscan import SecurityScannerValidator
|
||||||
from util.config.validators.validate_signer import SignerValidator
|
from util.config.validators.validate_signer import SignerValidator
|
||||||
|
from util.config.validators.validate_torrent import BittorrentValidator
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
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)
|
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 = {
|
VALIDATORS = {
|
||||||
DatabaseValidator.name: DatabaseValidator.validate,
|
DatabaseValidator.name: DatabaseValidator.validate,
|
||||||
RedisValidator.name: RedisValidator.validate,
|
RedisValidator.name: RedisValidator.validate,
|
||||||
|
@ -290,5 +247,5 @@ VALIDATORS = {
|
||||||
KeystoneValidator.name: KeystoneValidator.validate,
|
KeystoneValidator.name: KeystoneValidator.validate,
|
||||||
SignerValidator.name: SignerValidator.validate,
|
SignerValidator.name: SignerValidator.validate,
|
||||||
SecurityScannerValidator.name: SecurityScannerValidator.validate,
|
SecurityScannerValidator.name: SecurityScannerValidator.validate,
|
||||||
'bittorrent': _validate_bittorrent,
|
BittorrentValidator.name: BittorrentValidator.validate,
|
||||||
}
|
}
|
||||||
|
|
28
util/config/validators/test/test_validate_torrent.py
Normal file
28
util/config/validators/test/test_validate_torrent.py
Normal file
|
@ -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]
|
53
util/config/validators/validate_torrent.py
Normal file
53
util/config/validators/validate_torrent.py
Normal file
|
@ -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)
|
Reference in a new issue