diff --git a/docs/about/release-notes.md b/docs/about/release-notes.md index 4796611d..2aeb47ea 100644 --- a/docs/about/release-notes.md +++ b/docs/about/release-notes.md @@ -21,6 +21,11 @@ The current and past members of the MkDocs team. * [@d0ugal](https://github.com/d0ugal/) * [@waylan](https://github.com/waylan/) +## Version 1.1.1 (in development) + +Bugfix: Ensure wheel is Python 3 only. +Bugfix: Clean up `dev_addr` validation and disallow `0.0.0.0`. + ## Version 1.1 (2020-02-22) ### Major Additions to Version 1.1 diff --git a/mkdocs/config/config_options.py b/mkdocs/config/config_options.py index 5fd61f1d..d9456f2d 100644 --- a/mkdocs/config/config_options.py +++ b/mkdocs/config/config_options.py @@ -1,6 +1,7 @@ import os from collections import Sequence, namedtuple from urllib.parse import urlparse +import ipaddress import markdown from mkdocs import utils, theme, plugins @@ -233,6 +234,12 @@ class IpAddress(OptionallyRequired): except Exception: raise ValidationError("Must be a string of format 'IP:PORT'") + if host != 'localhost': + try: + ipaddress.ip_address(host) + except ValueError as e: + raise ValidationError(e) + try: port = int(port) except Exception: @@ -244,6 +251,15 @@ class IpAddress(OptionallyRequired): return Address(host, port) + def post_validation(self, config, key_name): + host = config[key_name].host + if key_name == 'dev_addr' and host in ['0.0.0.0', '::']: + raise ValidationError( + ("The MkDocs' server is intended for development purposes only. " + "Therefore, '{}' is not a supported IP address. Please use a " + "third party production-ready server instead.").format(host) + ) + class URL(OptionallyRequired): """ diff --git a/mkdocs/tests/config/config_options_tests.py b/mkdocs/tests/config/config_options_tests.py index da55c1fc..5195b91d 100644 --- a/mkdocs/tests/config/config_options_tests.py +++ b/mkdocs/tests/config/config_options_tests.py @@ -105,12 +105,12 @@ class IpAddressTest(unittest.TestCase): self.assertEqual(value.port, 8000) def test_valid_IPv6_address(self): - addr = '[::1]:8000' + addr = '::1:8000' option = config_options.IpAddress() value = option.validate(addr) self.assertEqual(str(value), addr) - self.assertEqual(value.host, '[::1]') + self.assertEqual(value.host, '::1') self.assertEqual(value.port, 8000) def test_named_address(self): @@ -131,6 +131,13 @@ class IpAddressTest(unittest.TestCase): self.assertEqual(value.host, '127.0.0.1') self.assertEqual(value.port, 8000) + def test_invalid_address_range(self): + option = config_options.IpAddress() + self.assertRaises( + config_options.ValidationError, + option.validate, '277.0.0.1:8000' + ) + def test_invalid_address_format(self): option = config_options.IpAddress() self.assertRaises( @@ -159,6 +166,34 @@ class IpAddressTest(unittest.TestCase): option.validate, '127.0.0.1' ) + def test_disallowed_address(self): + option = config_options.IpAddress() + value = option.validate('0.0.0.0:8000') + self.assertRaises( + config_options.ValidationError, + option.post_validation, + {'dev_addr': value}, + 'dev_addr' + ) + + def test_disallowed_IPv6_address(self): + option = config_options.IpAddress() + value = option.validate(':::8000') + self.assertRaises( + config_options.ValidationError, + option.post_validation, + {'dev_addr': value}, + 'dev_addr' + ) + + def test_invalid_IPv6_address(self): + # The server will error out with this so we treat it as invalid. + option = config_options.IpAddress() + self.assertRaises( + config_options.ValidationError, + option.validate, '[::1]:8000' + ) + class URLTest(unittest.TestCase): diff --git a/mkdocs/tests/integration/complicated_config/mkdocs.yml b/mkdocs/tests/integration/complicated_config/mkdocs.yml index 5c203795..d1076dff 100644 --- a/mkdocs/tests/integration/complicated_config/mkdocs.yml +++ b/mkdocs/tests/integration/complicated_config/mkdocs.yml @@ -21,7 +21,7 @@ theme: copyright: "Dougal Matthews" google_analytics: ["1", "2"] -dev_addr: 0.0.0.0:8000 +dev_addr: ::1:8000 use_directory_urls: false repo_url: https://github.com/mkdocs/mkdocs/tree/master/mkdocs/tests/integration