Merge pull request #1165 from paddatrapper/feature/python-force-ssl

Use force_ssl in python apps
This commit is contained in:
Lucas Bickel 2021-01-24 10:28:32 +01:00 committed by GitHub
commit f029584985
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 117 additions and 27 deletions

View File

@ -31,10 +31,8 @@ containers.
### Setup
There are known bugs when using LibreTime behind a reverse proxy ([#957](https://github.com/LibreTime/libretime/issues/957)
tracks the issue and contains a temporary workaround). For SSL redirection to work, you
need two domains: one for LibreTime and one for Icecast. Here, these will be
`libretime.example.com` and `icecast.example.com`.
For SSL redirection to work, you need two domains: one for LibreTime and one for Icecast.
Here, these will be `libretime.example.com` and `icecast.example.com`.
You will also require two VMs, servers or containers. Alternatively the reverse proxy can
be located on the server, proxying connections to containers also on the host. Setting up

View File

@ -10,7 +10,7 @@ import sys
import time
import urllib.request, urllib.error, urllib.parse
import requests
import socket
import socket
import logging
import json
import base64
@ -67,6 +67,17 @@ api_config['api_base'] = 'api'
api_config['bin_dir'] = '/usr/lib/airtime/api_clients/'
api_config['update_metadata_on_tunein'] = 'update-metadata-on-tunein/api_key/%%api_key%%'
def get_protocol(config):
positive_values = ['Yes', 'yes', 'True', 'true', True]
port = config['general'].get('base_port', 80)
force_ssl = config['general'].get('force_ssl', False)
if force_ssl in positive_values:
protocol = 'https'
else:
protocol = config['general'].get('protocol')
if not protocol:
protocol = str(("http", "https")[int(port) == 443])
return protocol
################################################################################
@ -169,9 +180,11 @@ class RequestProvider(object):
self.requests = {}
if self.config["general"]["base_dir"].startswith("/"):
self.config["general"]["base_dir"] = self.config["general"]["base_dir"][1:]
protocol = get_protocol(self.config)
self.url = ApcUrl("%s://%s:%s/%s%s/%s" \
% (str(("http", "https")[int(self.config["general"]["base_port"]) == 443]),
self.config["general"]["base_url"], str(self.config["general"]["base_port"]),
% (protocol, self.config["general"]["base_url"],
str(self.config["general"]["base_port"]),
self.config["general"]["base_dir"], self.config["api_base"],
'%%action%%'))
# Now we must discover the possible actions
@ -208,7 +221,7 @@ class AirtimeApiClient(object):
def __get_airtime_version(self):
try: return self.services.version_url()['airtime_version']
except Exception: return -1
def __get_api_version(self):
try: return self.services.version_url()['api_version']
except Exception: return -1
@ -331,8 +344,9 @@ class AirtimeApiClient(object):
# TODO : Make other methods in this class use this this method.
if self.config["general"]["base_dir"].startswith("/"):
self.config["general"]["base_dir"] = self.config["general"]["base_dir"][1:]
protocol = get_protocol(self.config)
url = "%s://%s:%s/%s%s/%s" % \
(str(("http", "https")[int(self.config["general"]["base_port"]) == 443]),
(protocol,
self.config["general"]["base_url"], str(self.config["general"]["base_port"]),
self.config["general"]["base_dir"], self.config["api_base"],
self.config[config_action_key])
@ -343,9 +357,9 @@ class AirtimeApiClient(object):
"""Constructs the base url for RESTful requests"""
if self.config["general"]["base_dir"].startswith("/"):
self.config["general"]["base_dir"] = self.config["general"]["base_dir"][1:]
protocol = get_protocol(self.config)
url = "%s://%s:@%s:%s/%s/%s" % \
(str(("http", "https")[int(self.config["general"]["base_port"]) == 443]),
self.config["general"]["api_key"],
(protocol, self.config["general"]["api_key"],
self.config["general"]["base_url"], str(self.config["general"]["base_port"]),
self.config["general"]["base_dir"],
self.config[config_action_key])

View File

@ -5,7 +5,7 @@ class TestApcUrl(unittest.TestCase):
def test_init(self):
url = "/testing"
u = ApcUrl(url)
self.assertEqual( u.base_url, url)
self.assertEqual(u.base_url, url)
def test_params_1(self):
u = ApcUrl("/testing/%%key%%")

View File

@ -0,0 +1,75 @@
import unittest
import configparser
from api_clients.api_client import get_protocol
def get_force_ssl(value, useConfigParser):
config = {}
if useConfigParser:
config = configparser.ConfigParser()
config['general'] = {
'base_port': 80,
'force_ssl': value,
}
return get_protocol(config)
class TestGetProtocol(unittest.TestCase):
def test_dict_config_empty_http(self):
config = {'general': {}}
protocol = get_protocol(config)
self.assertEqual(protocol, 'http')
def test_dict_config_http(self):
config = {
'general': {
'base_port': 80,
},
}
protocol = get_protocol(config)
self.assertEqual(protocol, 'http')
def test_dict_config_https(self):
config = {
'general': {
'base_port': 443,
},
}
protocol = get_protocol(config)
self.assertEqual(protocol, 'https')
def test_dict_config_force_https(self):
postive_values = ['yes', 'Yes', 'True', 'true', True]
negative_values = ['no', 'No', 'False', 'false', False]
for value in postive_values:
self.assertEqual(get_force_ssl(value, False), 'https')
for value in negative_values:
self.assertEqual(get_force_ssl(value, False), 'http')
def test_configparser_config_empty_http(self):
config = configparser.ConfigParser()
config['general'] = {}
protocol = get_protocol(config)
self.assertEqual(protocol, 'http')
def test_configparser_config_http(self):
config = configparser.ConfigParser()
config['general'] = {
'base_port': 80,
}
protocol = get_protocol(config)
self.assertEqual(protocol, 'http')
def test_configparser_config_https(self):
config = configparser.ConfigParser()
config['general'] = {
'base_port': 443,
}
protocol = get_protocol(config)
self.assertEqual(protocol, 'https')
def test_configparser_config_force_https(self):
postive_values = ['yes', 'Yes', 'True', 'true', True]
negative_values = ['no', 'No', 'False', 'false', False]
for value in postive_values:
self.assertEqual(get_force_ssl(value, True), 'https')
for value in negative_values:
self.assertEqual(get_force_ssl(value, True), 'http')

View File

@ -13,11 +13,14 @@ class TestRequestProvider(unittest.TestCase):
self.cfg['general']['base_url'] = 'localhost'
self.cfg['general']['api_key'] = 'TEST_KEY'
self.cfg['api_base'] = 'api'
def test_test(self):
self.assertTrue('general' in self.cfg)
def test_init(self):
rp = RequestProvider(self.cfg)
self.assertTrue( len( rp.available_requests() ) > 0 )
def test_contains(self):
rp = RequestProvider(self.cfg)
methods = ['upload_recorded', 'update_media_url', 'list_all_db_files']

View File

@ -67,14 +67,14 @@ class PypoFile(Thread):
CONFIG_SECTION = "general"
username = self._config.get(CONFIG_SECTION, 'api_key')
baseurl = self._config.get(CONFIG_SECTION, 'base_url')
try:
port = self._config.get(CONFIG_SECTION, 'base_port')
except NoOptionError as e:
port = 80
try:
protocol = self._config.get(CONFIG_SECTION, 'protocol')
except NoOptionError as e:
protocol = str(("http", "https")[int(port) == 443])
port = self._config.get(CONFIG_SECTION, 'base_port', 80)
if self._config.getboolean(CONFIG_SECTION, 'force_ssl', fallback=False):
protocol = 'https'
else:
try:
protocol = self._config.get(CONFIG_SECTION, 'protocol')
except NoOptionError as e:
protocol = str(("http", "https")[int(port) == 443])
try:
host = [protocol, baseurl, port]
@ -84,15 +84,15 @@ class PypoFile(Thread):
media_item["id"])
with open(dst, "wb") as handle:
response = requests.get(url, auth=requests.auth.HTTPBasicAuth(username, ''), stream=True, verify=False)
if not response.ok:
self.logger.error(response)
raise Exception("%s - Error occurred downloading file" % response.status_code)
for chunk in response.iter_content(1024):
if not chunk:
break
handle.write(chunk)
#make file world readable and owner writable
@ -160,11 +160,11 @@ class PypoFile(Thread):
"""
Remove this media_item from the dictionary. On the next iteration
(from the main function) we won't consider it for prioritization
(from the main function) we won't consider it for prioritization
anymore. If on the next iteration we have received a new schedule,
it is very possible we will have to deal with the same media_items
it is very possible we will have to deal with the same media_items
again. In this situation, the worst possible case is that we try to
copy the file again and realize we already have it (thus aborting the copy).
copy the file again and realize we already have it (thus aborting the copy).
"""
del schedule[highest_priority]
@ -179,7 +179,7 @@ class PypoFile(Thread):
logging.debug("Failed to open config file at %s: %s" % (config_path, e.strerror))
sys.exit()
except Exception as e:
logging.debug(e.strerror)
logging.debug(e.strerror)
sys.exit()
return config