From e1c2c17cf6ecf84dfd00d13fb87f696f82a8865f Mon Sep 17 00:00:00 2001
From: Brice Gros
Date: Fri, 10 Jan 2020 10:14:52 +0100
Subject: [PATCH 01/15] add http_user field to Host table
---
.gitignore | 1 +
.vscode/settings.json | 3 +
CHANGES.rst | 5 +
Pipfile | 27 +
Pipfile.lock | 469 ++++++++++++++++++
src/nsupdate/api/views.py | 24 +-
.../main/migrations/0013_host_http_user.py | 19 +
src/nsupdate/main/models.py | 28 ++
.../includes/tabbed_router_configuration.html | 50 +-
9 files changed, 588 insertions(+), 38 deletions(-)
create mode 100644 .vscode/settings.json
create mode 100644 Pipfile
create mode 100644 Pipfile.lock
create mode 100644 src/nsupdate/main/migrations/0013_host_http_user.py
diff --git a/.gitignore b/.gitignore
index d0abbdd3..be6e9ad1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+.venv
*.log
*.pot
*.pyc
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 00000000..fa1b4623
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+ "python.pythonPath": ".venv\\Scripts\\python.exe"
+}
\ No newline at end of file
diff --git a/CHANGES.rst b/CHANGES.rst
index 45c1c8be..bbd5700e 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -7,6 +7,11 @@ AFTER that, you can upgrade to 0.10.x or any later version (and then run the
migrations for that version). For upgrading and migration help, please see
the docs that match the version you are upgrading to.
+Release 0.13.0-alternative
+---------------------------------
+
+New Features:
+ - use a http user different from the fqdn of the host due to limitation in the length of the username from some routers
Release 0.13.0 (not released yet)
---------------------------------
diff --git a/Pipfile b/Pipfile
new file mode 100644
index 00000000..e9c85129
--- /dev/null
+++ b/Pipfile
@@ -0,0 +1,27 @@
+[[source]]
+name = "pypi"
+url = "https://pypi.org/simple"
+verify_ssl = true
+
+[dev-packages]
+
+[packages]
+dnspython = "*"
+netaddr = "*"
+django-bootstrap-form = "*"
+django-referrer-policy = "*"
+django-registration-redux = "*"
+django-extensions = "*"
+social-auth-app-django = "*"
+requests = "*"
+setuptools-scm = "*"
+django-debug-toolbar = "*"
+pytest = ">=3.6"
+pytest-django = "*"
+pytest-pep8 = "*"
+Django = "~=2.2.0"
+Sphinx = "*"
+nsupdate = {editable = true,path = "."}
+
+[requires]
+python_version = "3.6"
diff --git a/Pipfile.lock b/Pipfile.lock
new file mode 100644
index 00000000..2d3f0018
--- /dev/null
+++ b/Pipfile.lock
@@ -0,0 +1,469 @@
+{
+ "_meta": {
+ "hash": {
+ "sha256": "a1ae78750069722a3b9c6fbdf90f93b55273610657eac2b7abe5ef927b536869"
+ },
+ "pipfile-spec": 6,
+ "requires": {
+ "python_version": "3.6"
+ },
+ "sources": [
+ {
+ "name": "pypi",
+ "url": "https://pypi.org/simple",
+ "verify_ssl": true
+ }
+ ]
+ },
+ "default": {
+ "alabaster": {
+ "hashes": [
+ "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359",
+ "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"
+ ],
+ "version": "==0.7.12"
+ },
+ "apipkg": {
+ "hashes": [
+ "sha256:37228cda29411948b422fae072f57e31d3396d2ee1c9783775980ee9c9990af6",
+ "sha256:58587dd4dc3daefad0487f6d9ae32b4542b185e1c36db6993290e7c41ca2b47c"
+ ],
+ "version": "==1.5"
+ },
+ "atomicwrites": {
+ "hashes": [
+ "sha256:03472c30eb2c5d1ba9227e4c2ca66ab8287fbfbbda3888aa93dc2e28fc6811b4",
+ "sha256:75a9445bac02d8d058d5e1fe689654ba5a6556a1dfd8ce6ec55a0ed79866cfa6"
+ ],
+ "markers": "sys_platform == 'win32'",
+ "version": "==1.3.0"
+ },
+ "attrs": {
+ "hashes": [
+ "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c",
+ "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"
+ ],
+ "version": "==19.3.0"
+ },
+ "babel": {
+ "hashes": [
+ "sha256:1aac2ae2d0d8ea368fa90906567f5c08463d98ade155c0c4bfedd6a0f7160e38",
+ "sha256:d670ea0b10f8b723672d3a6abeb87b565b244da220d76b4dba1b66269ec152d4"
+ ],
+ "version": "==2.8.0"
+ },
+ "certifi": {
+ "hashes": [
+ "sha256:017c25db2a153ce562900032d5bc68e9f191e44e9a0f762f373977de9df1fbb3",
+ "sha256:25b64c7da4cd7479594d035c08c2d809eb4aab3a26e5a990ea98cc450c320f1f"
+ ],
+ "version": "==2019.11.28"
+ },
+ "chardet": {
+ "hashes": [
+ "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
+ "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
+ ],
+ "version": "==3.0.4"
+ },
+ "colorama": {
+ "hashes": [
+ "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff",
+ "sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"
+ ],
+ "markers": "sys_platform == 'win32'",
+ "version": "==0.4.3"
+ },
+ "defusedxml": {
+ "hashes": [
+ "sha256:6687150770438374ab581bb7a1b327a847dd9c5749e396102de3fad4e8a3ef93",
+ "sha256:f684034d135af4c6cbb949b8a4d2ed61634515257a67299e5f940fbaa34377f5"
+ ],
+ "markers": "python_version >= '3.0'",
+ "version": "==0.6.0"
+ },
+ "django": {
+ "hashes": [
+ "sha256:662a1ff78792e3fd77f16f71b1f31149489434de4b62a74895bd5d6534e635a5",
+ "sha256:687c37153486cf26c3fdcbdd177ef16de38dc3463f094b5f9c9955d91f277b14"
+ ],
+ "index": "pypi",
+ "version": "==2.2.9"
+ },
+ "django-bootstrap-form": {
+ "hashes": [
+ "sha256:de3f7893e515352834d446c441c0cb861637f92cebbe59d8229469c6cd3dc640"
+ ],
+ "index": "pypi",
+ "version": "==3.4"
+ },
+ "django-debug-toolbar": {
+ "hashes": [
+ "sha256:24c157bc6c0e1648e0a6587511ecb1b007a00a354ce716950bff2de12693e7a8",
+ "sha256:77cfba1d6e91b9bc3d36dc7dc74a9bb80be351948db5f880f2562a0cbf20b6c5"
+ ],
+ "index": "pypi",
+ "version": "==2.1"
+ },
+ "django-extensions": {
+ "hashes": [
+ "sha256:a9db7c56a556d244184f589f2437b4228de86ee45e5ebb837fb20c6d54e95ea5",
+ "sha256:b58320d3fe3d6ae7d1d8e38959713fa92272f4921e662d689058d942a5b444f7"
+ ],
+ "index": "pypi",
+ "version": "==2.2.5"
+ },
+ "django-referrer-policy": {
+ "hashes": [
+ "sha256:09e134324fa08c10efc12244a4bae7aee5defa7d332b92c603b09258c854615a"
+ ],
+ "index": "pypi",
+ "version": "==1.0"
+ },
+ "django-registration-redux": {
+ "hashes": [
+ "sha256:1aaf08c9c16b7f185ffa36e7251c7a6149fe953f5af21c4f1e01cbe03902520b",
+ "sha256:5998a8dbee2a84d66cd56a61c4fb6b1a5be801b083fb1ef53ba04939d8a44606"
+ ],
+ "index": "pypi",
+ "version": "==2.7"
+ },
+ "dnspython": {
+ "hashes": [
+ "sha256:36c5e8e38d4369a08b6780b7f27d790a292b2b08eea01607865bf0936c558e01",
+ "sha256:f69c21288a962f4da86e56c4905b49d11aba7938d3d740e80d9e366ee4f1632d"
+ ],
+ "index": "pypi",
+ "version": "==1.16.0"
+ },
+ "docutils": {
+ "hashes": [
+ "sha256:6c4f696463b79f1fb8ba0c594b63840ebd41f059e92b31957c46b74a4599b6d0",
+ "sha256:9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827",
+ "sha256:a2aeea129088da402665e92e0b25b04b073c04b2dce4ab65caaa38b7ce2e1a99"
+ ],
+ "version": "==0.15.2"
+ },
+ "execnet": {
+ "hashes": [
+ "sha256:cacb9df31c9680ec5f95553976c4da484d407e85e41c83cb812aa014f0eddc50",
+ "sha256:d4efd397930c46415f62f8a31388d6be4f27a91d7550eb79bc64a756e0056547"
+ ],
+ "version": "==1.7.1"
+ },
+ "idna": {
+ "hashes": [
+ "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407",
+ "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c"
+ ],
+ "version": "==2.8"
+ },
+ "imagesize": {
+ "hashes": [
+ "sha256:6965f19a6a2039c7d48bca7dba2473069ff854c36ae6f19d2cde309d998228a1",
+ "sha256:b1f6b5a4eab1f73479a50fb79fcf729514a900c341d8503d62a62dbc4127a2b1"
+ ],
+ "version": "==1.2.0"
+ },
+ "importlib-metadata": {
+ "hashes": [
+ "sha256:073a852570f92da5f744a3472af1b61e28e9f78ccf0c9117658dc32b15de7b45",
+ "sha256:d95141fbfa7ef2ec65cfd945e2af7e5a6ddbd7c8d9a25e66ff3be8e3daf9f60f"
+ ],
+ "markers": "python_version < '3.8'",
+ "version": "==1.3.0"
+ },
+ "jinja2": {
+ "hashes": [
+ "sha256:74320bb91f31270f9551d46522e33af46a80c3d619f4a4bf42b3164d30b5911f",
+ "sha256:9fe95f19286cfefaa917656583d020be14e7859c6b0252588391e47db34527de"
+ ],
+ "version": "==2.10.3"
+ },
+ "markupsafe": {
+ "hashes": [
+ "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473",
+ "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161",
+ "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235",
+ "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5",
+ "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff",
+ "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b",
+ "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1",
+ "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e",
+ "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183",
+ "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66",
+ "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1",
+ "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1",
+ "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e",
+ "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b",
+ "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905",
+ "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735",
+ "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d",
+ "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e",
+ "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d",
+ "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c",
+ "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21",
+ "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2",
+ "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5",
+ "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b",
+ "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6",
+ "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f",
+ "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f",
+ "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7"
+ ],
+ "version": "==1.1.1"
+ },
+ "more-itertools": {
+ "hashes": [
+ "sha256:b84b238cce0d9adad5ed87e745778d20a3f8487d0f0cb8b8a586816c7496458d",
+ "sha256:c833ef592a0324bcc6a60e48440da07645063c453880c9477ceb22490aec1564"
+ ],
+ "version": "==8.0.2"
+ },
+ "netaddr": {
+ "hashes": [
+ "sha256:38aeec7cdd035081d3a4c306394b19d677623bf76fa0913f6695127c7753aefd",
+ "sha256:56b3558bd71f3f6999e4c52e349f38660e54a7a8a9943335f73dfc96883e08ca"
+ ],
+ "index": "pypi",
+ "version": "==0.7.19"
+ },
+ "nsupdate": {
+ "editable": true,
+ "path": "."
+ },
+ "oauthlib": {
+ "hashes": [
+ "sha256:bee41cc35fcca6e988463cacc3bcb8a96224f470ca547e697b604cc697b2f889",
+ "sha256:df884cd6cbe20e32633f1db1072e9356f53638e4361bef4e8b03c9127c9328ea"
+ ],
+ "version": "==3.1.0"
+ },
+ "packaging": {
+ "hashes": [
+ "sha256:aec3fdbb8bc9e4bb65f0634b9f551ced63983a529d6a8931817d52fdd0816ddb",
+ "sha256:fe1d8331dfa7cc0a883b49d75fc76380b2ab2734b220fbb87d774e4fd4b851f8"
+ ],
+ "version": "==20.0"
+ },
+ "pep8": {
+ "hashes": [
+ "sha256:b22cfae5db09833bb9bd7c8463b53e1a9c9b39f12e304a8d0bba729c501827ee",
+ "sha256:fe249b52e20498e59e0b5c5256aa52ee99fc295b26ec9eaa85776ffdb9fe6374"
+ ],
+ "version": "==1.7.1"
+ },
+ "pluggy": {
+ "hashes": [
+ "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0",
+ "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"
+ ],
+ "version": "==0.13.1"
+ },
+ "py": {
+ "hashes": [
+ "sha256:5e27081401262157467ad6e7f851b7aa402c5852dbcb3dae06768434de5752aa",
+ "sha256:c20fdd83a5dbc0af9efd622bee9a5564e278f6380fffcacc43ba6f43db2813b0"
+ ],
+ "version": "==1.8.1"
+ },
+ "pygments": {
+ "hashes": [
+ "sha256:2a3fe295e54a20164a9df49c75fa58526d3be48e14aceba6d6b1e8ac0bfd6f1b",
+ "sha256:98c8aa5a9f778fcd1026a17361ddaf7330d1b7c62ae97c3bb0ae73e0b9b6b0fe"
+ ],
+ "version": "==2.5.2"
+ },
+ "pyjwt": {
+ "hashes": [
+ "sha256:5c6eca3c2940464d106b99ba83b00c6add741c9becaec087fb7ccdefea71350e",
+ "sha256:8d59a976fb773f3e6a39c85636357c4f0e242707394cadadd9814f5cbaa20e96"
+ ],
+ "version": "==1.7.1"
+ },
+ "pyparsing": {
+ "hashes": [
+ "sha256:4c830582a84fb022400b85429791bc551f1f4871c33f23e44f353119e92f969f",
+ "sha256:c342dccb5250c08d45fd6f8b4a559613ca603b57498511740e65cd11a2e7dcec"
+ ],
+ "version": "==2.4.6"
+ },
+ "pytest": {
+ "hashes": [
+ "sha256:6b571215b5a790f9b41f19f3531c53a45cf6bb8ef2988bc1ff9afb38270b25fa",
+ "sha256:e41d489ff43948babd0fad7ad5e49b8735d5d55e26628a58673c39ff61d95de4"
+ ],
+ "index": "pypi",
+ "version": "==5.3.2"
+ },
+ "pytest-cache": {
+ "hashes": [
+ "sha256:be7468edd4d3d83f1e844959fd6e3fd28e77a481440a7118d430130ea31b07a9"
+ ],
+ "version": "==1.0"
+ },
+ "pytest-django": {
+ "hashes": [
+ "sha256:17592f06d51c2ef4b7a0fb24aa32c8b6998506a03c8439606cb96db160106659",
+ "sha256:ef3d15b35ed7e46293475e6f282e71a53bcd8c6f87bdc5d5e7ad0f4d49352127"
+ ],
+ "index": "pypi",
+ "version": "==3.7.0"
+ },
+ "pytest-pep8": {
+ "hashes": [
+ "sha256:032ef7e5fa3ac30f4458c73e05bb67b0f036a8a5cb418a534b3170f89f120318"
+ ],
+ "index": "pypi",
+ "version": "==1.0.6"
+ },
+ "python3-openid": {
+ "hashes": [
+ "sha256:0086da6b6ef3161cfe50fb1ee5cceaf2cda1700019fda03c2c5c440ca6abe4fa",
+ "sha256:628d365d687e12da12d02c6691170f4451db28d6d68d050007e4a40065868502"
+ ],
+ "markers": "python_version >= '3.0'",
+ "version": "==3.1.0"
+ },
+ "pytz": {
+ "hashes": [
+ "sha256:1c557d7d0e871de1f5ccd5833f60fb2550652da6be2693c1e02300743d21500d",
+ "sha256:b02c06db6cf09c12dd25137e563b31700d3b80fcc4ad23abb7a315f2789819be"
+ ],
+ "version": "==2019.3"
+ },
+ "requests": {
+ "hashes": [
+ "sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4",
+ "sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31"
+ ],
+ "index": "pypi",
+ "version": "==2.22.0"
+ },
+ "requests-oauthlib": {
+ "hashes": [
+ "sha256:7f71572defaecd16372f9006f33c2ec8c077c3cfa6f5911a9a90202beb513f3d",
+ "sha256:b4261601a71fd721a8bd6d7aa1cc1d6a8a93b4a9f5e96626f8e4d91e8beeaa6a"
+ ],
+ "version": "==1.3.0"
+ },
+ "setuptools-scm": {
+ "hashes": [
+ "sha256:1f11cb2eea431346d46589c2dafcafe2e7dc1c7b2c70bc4c3752d2048ad5c148",
+ "sha256:bd25e1fb5e4d603dcf490f1fde40fb4c595b357795674c3e5cb7f6217ab39ea5"
+ ],
+ "index": "pypi",
+ "version": "==3.3.3"
+ },
+ "six": {
+ "hashes": [
+ "sha256:1f1b7d42e254082a9db6279deae68afb421ceba6158efa6131de7b3003ee93fd",
+ "sha256:30f610279e8b2578cab6db20741130331735c781b56053c59c4076da27f06b66"
+ ],
+ "version": "==1.13.0"
+ },
+ "snowballstemmer": {
+ "hashes": [
+ "sha256:209f257d7533fdb3cb73bdbd24f436239ca3b2fa67d56f6ff88e86be08cc5ef0",
+ "sha256:df3bac3df4c2c01363f3dd2cfa78cce2840a79b9f1c2d2de9ce8d31683992f52"
+ ],
+ "version": "==2.0.0"
+ },
+ "social-auth-app-django": {
+ "hashes": [
+ "sha256:6d0dd18c2d9e71ca545097d57b44d26f59e624a12833078e8e52f91baf849778",
+ "sha256:9237e3d7b6f6f59494c3b02e0cce6efc69c9d33ad9d1a064e3b2318bcbe89ae3",
+ "sha256:f151396e5b16e2eee12cd2e211004257826ece24fc4ae97a147df386c1cd7082"
+ ],
+ "index": "pypi",
+ "version": "==3.1.0"
+ },
+ "social-auth-core": {
+ "hashes": [
+ "sha256:47cd2458c8fefd02466b0c514643e02ad8b61d8b4b69f7573e80882e3a97b0f0",
+ "sha256:8320666548a532eb158968eda542bbe1863682357c432d8c4e28034a7f1e3b58",
+ "sha256:d81ed681e3c0722300b61a0792c5db5d21206793f95ca810f010c1cc931c8d89"
+ ],
+ "version": "==3.2.0"
+ },
+ "sphinx": {
+ "hashes": [
+ "sha256:298537cb3234578b2d954ff18c5608468229e116a9757af3b831c2b2b4819159",
+ "sha256:e6e766b74f85f37a5f3e0773a1e1be8db3fcb799deb58ca6d18b70b0b44542a5"
+ ],
+ "index": "pypi",
+ "version": "==2.3.1"
+ },
+ "sphinxcontrib-applehelp": {
+ "hashes": [
+ "sha256:edaa0ab2b2bc74403149cb0209d6775c96de797dfd5b5e2a71981309efab3897",
+ "sha256:fb8dee85af95e5c30c91f10e7eb3c8967308518e0f7488a2828ef7bc191d0d5d"
+ ],
+ "version": "==1.0.1"
+ },
+ "sphinxcontrib-devhelp": {
+ "hashes": [
+ "sha256:6c64b077937330a9128a4da74586e8c2130262f014689b4b89e2d08ee7294a34",
+ "sha256:9512ecb00a2b0821a146736b39f7aeb90759834b07e81e8cc23a9c70bacb9981"
+ ],
+ "version": "==1.0.1"
+ },
+ "sphinxcontrib-htmlhelp": {
+ "hashes": [
+ "sha256:4670f99f8951bd78cd4ad2ab962f798f5618b17675c35c5ac3b2132a14ea8422",
+ "sha256:d4fd39a65a625c9df86d7fa8a2d9f3cd8299a3a4b15db63b50aac9e161d8eff7"
+ ],
+ "version": "==1.0.2"
+ },
+ "sphinxcontrib-jsmath": {
+ "hashes": [
+ "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178",
+ "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"
+ ],
+ "version": "==1.0.1"
+ },
+ "sphinxcontrib-qthelp": {
+ "hashes": [
+ "sha256:513049b93031beb1f57d4daea74068a4feb77aa5630f856fcff2e50de14e9a20",
+ "sha256:79465ce11ae5694ff165becda529a600c754f4bc459778778c7017374d4d406f"
+ ],
+ "version": "==1.0.2"
+ },
+ "sphinxcontrib-serializinghtml": {
+ "hashes": [
+ "sha256:c0efb33f8052c04fd7a26c0a07f1678e8512e0faec19f4aa8f2473a8b81d5227",
+ "sha256:db6615af393650bf1151a6cd39120c29abaf93cc60db8c48eb2dddbfdc3a9768"
+ ],
+ "version": "==1.1.3"
+ },
+ "sqlparse": {
+ "hashes": [
+ "sha256:40afe6b8d4b1117e7dff5504d7a8ce07d9a1b15aeeade8a2d10f130a834f8177",
+ "sha256:7c3dca29c022744e95b547e867cee89f4fce4373f3549ccd8797d8eb52cdb873"
+ ],
+ "version": "==0.3.0"
+ },
+ "urllib3": {
+ "hashes": [
+ "sha256:a8a318824cc77d1fd4b2bec2ded92646630d7fe8619497b142c84a9e6f5a7293",
+ "sha256:f3c5fd51747d450d4dcf6f923c81f78f811aab8205fda64b0aba34a4e48b0745"
+ ],
+ "version": "==1.25.7"
+ },
+ "wcwidth": {
+ "hashes": [
+ "sha256:8fd29383f539be45b20bd4df0dc29c20ba48654a41e661925e612311e9f3c603",
+ "sha256:f28b3e8a6483e5d49e7f8949ac1a78314e740333ae305b4ba5defd3e74fb37a8"
+ ],
+ "version": "==0.1.8"
+ },
+ "zipp": {
+ "hashes": [
+ "sha256:3718b1cbcd963c7d4c5511a8240812904164b7f381b647143a89d3b98f9bcd8e",
+ "sha256:f06903e9f1f43b12d371004b4ac7b06ab39a44adc747266928ae6debfa7b3335"
+ ],
+ "version": "==0.6.0"
+ }
+ },
+ "develop": {}
+}
diff --git a/src/nsupdate/api/views.py b/src/nsupdate/api/views.py
index bd7cd6ec..c8f01b06 100644
--- a/src/nsupdate/api/views.py
+++ b/src/nsupdate/api/views.py
@@ -139,18 +139,18 @@ def check_api_auth(username, password, logger=None):
"""
Check username and password against our database.
- :param username: http basic auth username (== fqdn)
+ :param username: http basic auth username
:param password: update password
:return: host object if authenticated, None otherwise.
"""
- fqdn = username
try:
- host = Host.get_by_fqdn(fqdn)
+ host = Host.get_by_http_user(username)
except ValueError:
# logging this at debug level because otherwise it fills our logs...
- logger.debug('%s - received bad credentials (auth username == dyndns hostname not in our hosts DB)' % (fqdn, ))
+ logger.debug('%s - received bad credentials' % (username, ))
return None
if host is not None:
+ fqdn = host.get_fqdn()
ok = check_password(password, host.update_secret)
success_msg = ('failure', 'success')[ok]
msg = "api authentication %s. [hostname: %s (given in basic auth)]" % (success_msg, fqdn, )
@@ -218,19 +218,17 @@ def get(self, request, logger=None, delete=False):
logger.debug('%s - received no auth' % (hostname, ))
return basic_challenge("authenticate to update DNS", 'badauth')
username, password = basic_authenticate(auth)
- if '.' not in username: # username MUST be the fqdn
- # specifically point to configuration errors on client side
- return Response('notfqdn')
- if username in settings.BAD_HOSTS:
- return Response('abuse', status=403)
host = check_api_auth(username, password)
if host is None:
return basic_challenge("authenticate to update DNS", 'badauth')
- logger.info("authenticated by update secret for host %s" % username)
+ fqdn = str(host.get_fqdn())
+ if fqdn in settings.BAD_HOSTS:
+ return Response('abuse', status=403)
+ logger.info("authenticated by update secret for host %s" % fqdn)
if hostname is None:
# as we use update_username == hostname, we can fall back to that:
- hostname = username
- elif hostname != username:
+ hostname = fqdn
+ elif hostname != fqdn:
if '.' not in hostname:
# specifically point to configuration errors on client side
result = 'notfqdn'
@@ -238,7 +236,7 @@ def get(self, request, logger=None, delete=False):
# maybe this host is owned by same person, but we can't know.
result = 'nohost' # or 'badauth'?
msg = ("rejecting to update wrong host %s (given in query string) "
- "[instead of %s (given in basic auth)]" % (hostname, username))
+ "[instead of %s (given in basic auth as user %s)]" % (hostname, fqdn, username))
logger.warning(msg)
host.register_client_result(msg, fault=True)
return Response(result)
diff --git a/src/nsupdate/main/migrations/0013_host_http_user.py b/src/nsupdate/main/migrations/0013_host_http_user.py
new file mode 100644
index 00000000..ba52bfbc
--- /dev/null
+++ b/src/nsupdate/main/migrations/0013_host_http_user.py
@@ -0,0 +1,19 @@
+# Generated by Django 2.2.9 on 2020-01-10 08:53
+
+from django.db import migrations, models
+import nsupdate.main.models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('main', '0012_auto_20191230_1729'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='host',
+ name='http_user',
+ field=models.CharField(default=nsupdate.main.models._http_user_generator, max_length=30, unique=True, verbose_name='http user'),
+ ),
+ ]
diff --git a/src/nsupdate/main/models.py b/src/nsupdate/main/models.py
index 5cc69cae..5322ff78 100644
--- a/src/nsupdate/main/models.py
+++ b/src/nsupdate/main/models.py
@@ -5,6 +5,8 @@
import re
import time
import base64
+from datetime import datetime
+import random
import dns.resolver
import dns.message
@@ -153,6 +155,13 @@ class Meta:
verbose_name_plural = _('domains')
ordering = ('name',)
+_HOST_HTTP_USER_MAX_LENGTH=30 # limit comes from an external application not accepting longer username
+def _http_user_generator():
+ dt = datetime.utcnow().strftime('%Y%m%d%H%m%S%f')
+ maxrange = pow(10, _HOST_HTTP_USER_MAX_LENGTH-len(dt))
+ randvalue = random.randrange(0, maxrange)
+ return f'{randvalue}{dt}'.zfill(_HOST_HTTP_USER_MAX_LENGTH)
+
@python_2_unicode_compatible
class Host(models.Model):
@@ -168,6 +177,13 @@ class Host(models.Model):
],
help_text=_("The name of your host."))
domain = models.ForeignKey(Domain, on_delete=models.CASCADE, verbose_name=_("domain"))
+ http_user = models.CharField(
+ _("http user"),
+ max_length=_HOST_HTTP_USER_MAX_LENGTH, # username used for http basic auth
+ unique=True,
+ null=False,
+ default=_http_user_generator
+ )
update_secret = models.CharField(
_("update secret"),
max_length=64, # secret gets hashed (on save) to salted sha1, 58 bytes str len
@@ -267,6 +283,18 @@ class Meta(object):
def get_fqdn(self):
return dnstools.FQDN(self.name, self.domain.name)
+ @classmethod
+ def get_by_http_user(cls, username, **kwargs):
+ try:
+ host = Host.objects.get(http_user=username, **kwargs)
+ except Host.DoesNotExist:
+ return None
+ except Host.MultipleObjectsReturned:
+ # should not happen, see Host.http_user should have unique=True
+ raise ValueError("get_by_http_user(%s) found more than 1 host" % fqdn)
+ else:
+ return host
+
@classmethod
def get_by_fqdn(cls, fqdn, **kwargs):
# Assuming subdomain has no dots (.) the fqdn is split at the first dot
diff --git a/src/nsupdate/main/templates/main/includes/tabbed_router_configuration.html b/src/nsupdate/main/templates/main/includes/tabbed_router_configuration.html
index d6eb88b1..51f8fcbf 100644
--- a/src/nsupdate/main/templates/main/includes/tabbed_router_configuration.html
+++ b/src/nsupdate/main/templates/main/includes/tabbed_router_configuration.html
@@ -49,11 +49,11 @@ {% trans "General configuration hints" %}
{% trans "For IPv4 updates:" %}
{% trans "For IPv6 updates:" %}
{% blocktrans trimmed %}
The IPs will be determined automatically using the remote address our service is seeing
@@ -75,7 +75,7 @@ {% trans "General configuration hints" %}
{% trans "Do HTTP Basic Auth with:" %}
- - {% trans "Username:" %} {{ host.get_fqdn|default:"<your fqdn>" }}
+ - {% trans "Username:" %} {{ host.http_user|default:"<your host http user>" }}
- {% trans "Password:" %} {{ update_secret|default:"<your secret>" }}
@@ -120,7 +120,7 @@ {% trans "Enter the following data:" %}
Dynamic DNS provider | Custom |
Update-URL | https://{{ WWW_IPV4_HOST }}/nic/update |
Domain Name | {{ host.get_fqdn|default:"<your hostname>" }} |
- User name | {{ host.get_fqdn|default:"<your hostname>" }} |
+ User name | {{ host.http_user|default:"<your http user>" }} |
Password | {{ update_secret|default:"<your secret>" }} |
{% trans "If you have IPv4 and IPv6" %}
@@ -146,7 +146,7 @@ {% trans "Enter the following data:" %}
Setting | Value |
DDNS Service | Custom |
DYNDNS Server | {{ WWW_IPV4_HOST }} |
- Username | {{ host.get_fqdn|default:"<your hostname>" }} |
+ Username | {{ host.http_user|default:"<your http user>" }} |
Password | {{ update_secret|default:"<your secret>" }} |
Hostname | {{ host.get_fqdn|default:"<your hostname>" }} |
URL | /nic/update? |
@@ -168,7 +168,7 @@ ddclient
use=web, web=http://{{ WWW_IPV4_HOST }}/myip
ssl=yes # yes = use https for updates
server={{ WWW_IPV4_HOST }}
-login={{ host.get_fqdn|default:"<your hostname>" }}
+login={{ host.http_user|default:"<your http user>" }}
password='{{ update_secret|default:"<your secret>" }}'
{{ host.get_fqdn|default:"<your hostname>" }}
@@ -181,7 +181,7 @@ ddclient
#usev6=if, if=eth0
#ssl=yes # yes = use https for updates
#server={{ WWW_IPV6_HOST }}
-#login={{ host.get_fqdn|default:"<your hostname>" }}
+#login={{ host.http_user|default:"<your http user>" }}
#password='{{ update_secret|default:"<your secret>" }}'
#{{ host.get_fqdn|default:"<your hostname>" }}
@@ -198,7 +198,7 @@ dyndnsc
# the detector dnswanip returns:
use_preset = nsupdate.info:ipv4
updater-hostname = {{ host.get_fqdn|default:"<your hostname>" }}
-updater-userid = {{ host.get_fqdn|default:"<your hostname>" }}
+updater-userid = {{ host.http_user|default:"<your http user>" }}
updater-password = {{ update_secret|default:"<your secret>" }}
detector = webcheck4
@@ -207,7 +207,7 @@ dyndnsc
# the detector dnswanip returns:
use_preset = nsupdate.info:ipv6
updater-hostname = {{ host.get_fqdn|default:"<your hostname>" }}
-updater-userid = {{ host.get_fqdn|default:"<your hostname>" }}
+updater-userid = {{ host.http_user|default:"<your http user>" }}
updater-password = {{ update_secret|default:"<your secret>" }}
detector = webcheck6
@@ -220,7 +220,7 @@ EdgeOS (ddclient)
interface pppoe0 {
service custom-nsupdate {
host-name {{ host.get_fqdn|default:"<your hostname>" }}
- login {{ host.get_fqdn|default:"<your hostname>" }}
+ login {{ host.http_user|default:"<your http user>" }}
password {{ update_secret|default:"<your secret>" }}
protocol dyndns2
server {{ WWW_IPV4_HOST }}
@@ -244,7 +244,7 @@ {% trans "Enter the following data (and click ADD afterwards):" %}
Service | nsupdate.info |
Enabled | (check) |
Host Name | {{ host.get_fqdn|default:"<your hostname>" }} |
- User name | {{ host.get_fqdn|default:"<your hostname>" }} |
+ User name | {{ host.http_user|default:"<your http user>" }} |
Password | {{ update_secret|default:"<your secret>" }} |
@@ -261,7 +261,7 @@ {% trans "Enter the following data:" %}
Service Type | DynDNS |
Hostname | {{ host.get_fqdn|default:"<your hostname>" }} |
Server | {{ WWW_IPV4_HOST }} |
- Username | {{ host.get_fqdn|default:"<your hostname>" }} |
+ Username | {{ host.http_user|default:"<your http user>" }} |
Password | {{ update_secret|default:"<your secret>" }} |
@@ -275,7 +275,7 @@ inadyn ({% trans "verified with" %} 1.99.11)
system ipv4@nsupdate.info
ssl
- username {{ host.get_fqdn|default:"<your hostname>" }}
+ username {{ host.http_user|default:"<your http user>" }}
password {{ update_secret|default:"<your secret>" }}
alias {{ host.get_fqdn|default:"<your hostname>" }}
@@ -288,7 +288,7 @@ inadyn ({% trans "verified with" %} 2.1)
provider ipv4@nsupdate.info {
ssl = true
- username = {{ host.get_fqdn|default:"<your hostname>" }}
+ username = {{ host.http_user|default:"<your http user>" }}
password = {{ update_secret|default:"<your secret>" }}
hostname = {{ host.get_fqdn|default:"<your hostname>" }}
}
@@ -310,7 +310,7 @@ OpenWRT ({% trans "verified with" %} "Chaos Calmer")
option ip_url "http://{{ WWW_IPV4_HOST }}/myip"
option domain "{{ host.get_fqdn|default:"<your hostname>" }}"
- option username "{{ host.get_fqdn|default:"<your hostname>" }}"
+ option username "{{ host.http_user|default:"<your http user>" }}"
option password "{{ update_secret|default:"<your secret>" }}"
# for https support, first install wget with ssl support and
@@ -343,7 +343,7 @@ {% trans "Enter the following data:" %}
Interface to monitor | WAN {% trans "(most likely)" %} |
Interface to send from | WAN {% trans "(most likely)" %} |
Verbose logging | {% trans "(select this as long as you need it)" %} |
- Username | {{ host.get_fqdn|default:"<your hostname>" }} |
+ Username | {{ host.http_user|default:"<your http user>" }} |
Password | {{ update_secret|default:"<your secret>" }} |
Update URL | https://{{ WWW_IPV4_HOST }}/nic/update |
Result Match | good %IP%|nochg %IP% |
@@ -357,7 +357,7 @@ {% trans "Enter the following data:" %}
Setting | Value |
Provider | other Provider |
Domain name | {{ host.get_fqdn|default:"<your hostname>" }} |
- User name | {{ host.get_fqdn|default:"<your hostname>" }} |
+ User name | {{ host.http_user|default:"<your http user>" }} |
Password | {{ update_secret|default:"<your secret>" }} |
Update server address | https://{{ WWW_IPV4_HOST }} |
Protocol | https |
@@ -371,9 +371,9 @@ {% trans "Browser-based update client" %}
It periodically checks your IP and updates DNS if it changes.
{% endblocktrans %}
{% trans "URLs for browser / http user agent use" %}
{% trans "Important: Do not send an update if your IP did not change since last update!" %}
@@ -391,14 +391,14 @@ {% trans "URLs for browser / http user agent use" %}
{% trans "Giving the http basic auth username and password in the URL:" %}
{% trans "As above, but manually specifying the IP address:" %}
{% trans "Explanation of parameters:" %}
From abccf86cdcf93180c51383e21cfff8c2238701da Mon Sep 17 00:00:00 2001
From: Brice Gros
Date: Fri, 10 Jan 2020 15:24:20 +0100
Subject: [PATCH 02/15] WIP fix migration
---
.../main/migrations/0013_host_http_user.py | 21 ++++++++++++++++++-
1 file changed, 20 insertions(+), 1 deletion(-)
diff --git a/src/nsupdate/main/migrations/0013_host_http_user.py b/src/nsupdate/main/migrations/0013_host_http_user.py
index ba52bfbc..d052589e 100644
--- a/src/nsupdate/main/migrations/0013_host_http_user.py
+++ b/src/nsupdate/main/migrations/0013_host_http_user.py
@@ -3,6 +3,19 @@
from django.db import migrations, models
import nsupdate.main.models
+def gen_http_user(apps, schema_editor):
+ nsupdate.main.models._http_user_generator
+ Host = apps.get_model('main', 'Host')
+ http_user_set = set()
+ all_hosts = [row for row in Host.objects.all() ]
+ for row in all_hosts:
+ http_user = _http_user_generator()
+ while http_user in http_user_set:
+ http_user = _http_user_generator()
+ http_users.add(http_user)
+ row.http_user = http_user
+ for row in all_hosts:
+ row.save(update_fields=['http_user'])
class Migration(migrations.Migration):
@@ -14,6 +27,12 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='host',
name='http_user',
- field=models.CharField(default=nsupdate.main.models._http_user_generator, max_length=30, unique=True, verbose_name='http user'),
+ field=models.CharField(null=True, max_length=30, unique=True, verbose_name='http user'),
),
+ migrations.RunPython(gen_http_user, reverse_code=migrations.RunPython.noop),
+ migrations.AlterField(
+ model_name='host',
+ name='http_user',
+ field=models.CharField(null=False, default=nsupdate.main.models._http_user_generator),
+ )
]
From f34156282f43f91ae41b8ebb6f32535b12775977 Mon Sep 17 00:00:00 2001
From: Brice Gros
Date: Fri, 10 Jan 2020 16:16:16 +0100
Subject: [PATCH 03/15] Fix migration step
---
.../main/migrations/0013_host_http_user.py | 15 +++++++--------
src/nsupdate/main/models.py | 5 +++--
2 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/src/nsupdate/main/migrations/0013_host_http_user.py b/src/nsupdate/main/migrations/0013_host_http_user.py
index d052589e..daa3fdb2 100644
--- a/src/nsupdate/main/migrations/0013_host_http_user.py
+++ b/src/nsupdate/main/migrations/0013_host_http_user.py
@@ -3,20 +3,19 @@
from django.db import migrations, models
import nsupdate.main.models
+
def gen_http_user(apps, schema_editor):
- nsupdate.main.models._http_user_generator
Host = apps.get_model('main', 'Host')
http_user_set = set()
all_hosts = [row for row in Host.objects.all() ]
for row in all_hosts:
- http_user = _http_user_generator()
+ http_user = nsupdate.main.models._http_user_generator()
while http_user in http_user_set:
- http_user = _http_user_generator()
- http_users.add(http_user)
+ http_user = nsupdate.main.models._http_user_generator()
+ http_user_set.add(http_user)
row.http_user = http_user
for row in all_hosts:
row.save(update_fields=['http_user'])
-
class Migration(migrations.Migration):
dependencies = [
@@ -27,12 +26,12 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='host',
name='http_user',
- field=models.CharField(null=True, max_length=30, unique=True, verbose_name='http user'),
+ field=models.CharField(max_length=30, unique=True, verbose_name='http user', null=True, default=None),
),
migrations.RunPython(gen_http_user, reverse_code=migrations.RunPython.noop),
migrations.AlterField(
model_name='host',
name='http_user',
- field=models.CharField(null=False, default=nsupdate.main.models._http_user_generator),
- )
+ field=models.CharField(max_length=30, unique=True, verbose_name='http user', null=False, default=nsupdate.main.models._http_user_generator),
+ ),
]
diff --git a/src/nsupdate/main/models.py b/src/nsupdate/main/models.py
index 5322ff78..3dd63bcb 100644
--- a/src/nsupdate/main/models.py
+++ b/src/nsupdate/main/models.py
@@ -155,12 +155,13 @@ class Meta:
verbose_name_plural = _('domains')
ordering = ('name',)
-_HOST_HTTP_USER_MAX_LENGTH=30 # limit comes from an external application not accepting longer username
+_HOST_HTTP_USER_MAX_LENGTH=30 # limit comes from an external application not accepting longer username must be same than in Host.max_length
def _http_user_generator():
dt = datetime.utcnow().strftime('%Y%m%d%H%m%S%f')
maxrange = pow(10, _HOST_HTTP_USER_MAX_LENGTH-len(dt))
randvalue = random.randrange(0, maxrange)
- return f'{randvalue}{dt}'.zfill(_HOST_HTTP_USER_MAX_LENGTH)
+ username = f'{randvalue}{dt}'.zfill(_HOST_HTTP_USER_MAX_LENGTH)
+ return username
@python_2_unicode_compatible
From 720de2e8e38f2b905a4a6b24da01738729dc89f4 Mon Sep 17 00:00:00 2001
From: Brice Gros
Date: Fri, 10 Jan 2020 16:17:49 +0100
Subject: [PATCH 04/15] add missing line
---
src/nsupdate/main/migrations/0013_host_http_user.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/nsupdate/main/migrations/0013_host_http_user.py b/src/nsupdate/main/migrations/0013_host_http_user.py
index daa3fdb2..23ce4d2b 100644
--- a/src/nsupdate/main/migrations/0013_host_http_user.py
+++ b/src/nsupdate/main/migrations/0013_host_http_user.py
@@ -16,6 +16,7 @@ def gen_http_user(apps, schema_editor):
row.http_user = http_user
for row in all_hosts:
row.save(update_fields=['http_user'])
+
class Migration(migrations.Migration):
dependencies = [
From fcc1728423e7297aed056acd2203a3e0907bd504 Mon Sep 17 00:00:00 2001
From: Brice Gros
Date: Tue, 21 Jan 2020 15:44:04 +0100
Subject: [PATCH 05/15] use .format() instead of f-string for compatibility
with python 3.5
---
src/nsupdate/main/models.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/nsupdate/main/models.py b/src/nsupdate/main/models.py
index 3dd63bcb..6976343d 100644
--- a/src/nsupdate/main/models.py
+++ b/src/nsupdate/main/models.py
@@ -160,7 +160,7 @@ def _http_user_generator():
dt = datetime.utcnow().strftime('%Y%m%d%H%m%S%f')
maxrange = pow(10, _HOST_HTTP_USER_MAX_LENGTH-len(dt))
randvalue = random.randrange(0, maxrange)
- username = f'{randvalue}{dt}'.zfill(_HOST_HTTP_USER_MAX_LENGTH)
+ username = '{randvalue}{dt}'.format(randvalue=randvalue, dt=dt).zfill(_HOST_HTTP_USER_MAX_LENGTH)
return username
From 80f8d57269adf5a980482cd9a80fe660d6f5b852 Mon Sep 17 00:00:00 2001
From: Brice Gros
Date: Tue, 21 Jan 2020 15:57:36 +0100
Subject: [PATCH 06/15] update tests to use Host.http_user
---
conftest.py | 7 +++++--
src/nsupdate/api/_tests/test_api.py | 4 ++--
2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/conftest.py b/conftest.py
index 3c3fefcd..75190fcd 100644
--- a/conftest.py
+++ b/conftest.py
@@ -7,6 +7,7 @@
from random import randint
from nsupdate.main.dnstools import FQDN
+from nsupdate.main.models import _HOST_HTTP_USER_MAX_LENGTH
from django.conf import settings
@@ -39,6 +40,8 @@
from nsupdate.main.dnstools import update_ns, FQDN
+def to_http_user(hostname):
+ return hostname[:_HOST_HTTP_USER_MAX_LENGTH].zfill(_HOST_HTTP_USER_MAX_LENGTH)
@pytest.yield_fixture(scope="function")
def ddns_hostname():
@@ -96,10 +99,10 @@ def db_init(db): # note: db is a predefined fixture and required here to have t
)
# a Host for api / session update tests
hostname = TEST_HOST.host
- h = Host(name=hostname, domain=dt, created_by=u, netmask_ipv4=29, netmask_ipv6=64)
+ h = Host(name=hostname, domain=dt, created_by=u, netmask_ipv4=29, netmask_ipv6=64, http_user=to_http_user(hostname))
h.generate_secret(secret=TEST_SECRET)
hostname2 = TEST_HOST2.host
- h2 = Host(name=hostname2, domain=dt, created_by=u2, netmask_ipv4=29, netmask_ipv6=64)
+ h2 = Host(name=hostname2, domain=dt, created_by=u2, netmask_ipv4=29, netmask_ipv6=64, http_user=to_http_user(hostname))
h2.generate_secret(secret=TEST_SECRET2)
# "update other service" ddns_client feature
diff --git a/src/nsupdate/api/_tests/test_api.py b/src/nsupdate/api/_tests/test_api.py
index f6e072b6..8d42f0cc 100644
--- a/src/nsupdate/api/_tests/test_api.py
+++ b/src/nsupdate/api/_tests/test_api.py
@@ -13,7 +13,7 @@
from nsupdate.main.models import Domain
from nsupdate.api.views import basic_authenticate
-from conftest import TESTDOMAIN, TEST_HOST, TEST_HOST_RELATED, TEST_HOST2, TEST_SECRET, TEST_SECRET2
+from conftest import TESTDOMAIN, TEST_HOST, TEST_HOST_RELATED, TEST_HOST2, TEST_SECRET, TEST_SECRET2, to_http_user
USERNAME = 'test'
PASSWORD = 'pass'
@@ -45,7 +45,7 @@ def make_basic_auth_header(username, password):
# note: the coding dance in the next lines is to make sure we get str type
# on python 2 as well as on python 3 as str is the type we get in the auth
# object when practically running with a real web server.
- user_pass = u'%s:%s' % (username, password)
+ user_pass = u'%s:%s' % (to_http_user(username), password)
return 'Basic ' + str(base64.b64encode(user_pass.encode('utf-8')).decode('ascii'))
From 6b1cd88d3edb5192574f3dde8ae215269254acca Mon Sep 17 00:00:00 2001
From: Brice Gros
Date: Tue, 21 Jan 2020 16:20:55 +0100
Subject: [PATCH 07/15] fix typo
---
conftest.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/conftest.py b/conftest.py
index 75190fcd..58729153 100644
--- a/conftest.py
+++ b/conftest.py
@@ -102,7 +102,7 @@ def db_init(db): # note: db is a predefined fixture and required here to have t
h = Host(name=hostname, domain=dt, created_by=u, netmask_ipv4=29, netmask_ipv6=64, http_user=to_http_user(hostname))
h.generate_secret(secret=TEST_SECRET)
hostname2 = TEST_HOST2.host
- h2 = Host(name=hostname2, domain=dt, created_by=u2, netmask_ipv4=29, netmask_ipv6=64, http_user=to_http_user(hostname))
+ h2 = Host(name=hostname2, domain=dt, created_by=u2, netmask_ipv4=29, netmask_ipv6=64, http_user=to_http_user(hostname2))
h2.generate_secret(secret=TEST_SECRET2)
# "update other service" ddns_client feature
From 5b9bda87f2b7a96ce3bb8d1e62a9391f4e58fa73 Mon Sep 17 00:00:00 2001
From: Brice Gros
Date: Tue, 21 Jan 2020 16:35:58 +0100
Subject: [PATCH 08/15] apply to_http_user() only where it makes sense
---
src/nsupdate/api/_tests/test_api.py | 56 ++++++++++++++---------------
1 file changed, 28 insertions(+), 28 deletions(-)
diff --git a/src/nsupdate/api/_tests/test_api.py b/src/nsupdate/api/_tests/test_api.py
index 8d42f0cc..7c432892 100644
--- a/src/nsupdate/api/_tests/test_api.py
+++ b/src/nsupdate/api/_tests/test_api.py
@@ -45,7 +45,7 @@ def make_basic_auth_header(username, password):
# note: the coding dance in the next lines is to make sure we get str type
# on python 2 as well as on python 3 as str is the type we get in the auth
# object when practically running with a real web server.
- user_pass = u'%s:%s' % (to_http_user(username), password)
+ user_pass = u'%s:%s' % (username, password)
return 'Basic ' + str(base64.b64encode(user_pass.encode('utf-8')).decode('ascii'))
@@ -58,14 +58,14 @@ def test_basic_auth():
def test_nic_update_badauth(client):
response = client.get(reverse('nic_update'),
- HTTP_AUTHORIZATION=make_basic_auth_header(TEST_HOST, "wrong"))
+ HTTP_AUTHORIZATION=make_basic_auth_header(to_http_user(TEST_HOST), "wrong"))
assert response.status_code == 401
assert response.content == b'badauth'
def test_nic_update_authorized_nonexistent_host(client):
response = client.get(reverse('nic_update') + '?hostname=nonexistent.nsupdate.info',
- HTTP_AUTHORIZATION=make_basic_auth_header(TEST_HOST, TEST_SECRET))
+ HTTP_AUTHORIZATION=make_basic_auth_header(to_http_user(TEST_HOST), TEST_SECRET))
assert response.status_code == 200
# we must not get this updated, it doesn't exist in the database:
assert response.content == b'nohost'
@@ -73,7 +73,7 @@ def test_nic_update_authorized_nonexistent_host(client):
def test_nic_update_authorized_foreign_host(client):
response = client.get(reverse('nic_update') + '?hostname=%s' % (TEST_HOST2, ),
- HTTP_AUTHORIZATION=make_basic_auth_header(TEST_HOST, TEST_SECRET))
+ HTTP_AUTHORIZATION=make_basic_auth_header(to_http_user(TEST_HOST), TEST_SECRET))
assert response.status_code == 200
# we must not get this updated, this is a host of some other user!
assert response.content == b'nohost'
@@ -81,7 +81,7 @@ def test_nic_update_authorized_foreign_host(client):
def test_nic_update_authorized_not_fqdn_hostname(client):
response = client.get(reverse('nic_update') + '?hostname=test',
- HTTP_AUTHORIZATION=make_basic_auth_header(TEST_HOST, TEST_SECRET))
+ HTTP_AUTHORIZATION=make_basic_auth_header(to_http_user(TEST_HOST), TEST_SECRET))
assert response.status_code == 200
assert response.content == b'notfqdn'
@@ -95,21 +95,21 @@ def test_nic_update_authorized_not_fqdn_username(client):
def test_nic_update_authorized_invalid_ip1(client):
response = client.get(reverse('nic_update') + '?myip=1234',
- HTTP_AUTHORIZATION=make_basic_auth_header(TEST_HOST, TEST_SECRET))
+ HTTP_AUTHORIZATION=make_basic_auth_header(to_http_user(TEST_HOST), TEST_SECRET))
assert response.status_code == 200
assert response.content == b'dnserr'
def test_nic_update_authorized_invalid_ip2(client):
response = client.get(reverse('nic_update') + '?myip=%C3%A4%C3%BC%C3%B6',
- HTTP_AUTHORIZATION=make_basic_auth_header(TEST_HOST, TEST_SECRET))
+ HTTP_AUTHORIZATION=make_basic_auth_header(to_http_user(TEST_HOST), TEST_SECRET))
assert response.status_code == 200
assert response.content == b'dnserr'
def test_nic_update_authorized(client):
response = client.get(reverse('nic_update'),
- HTTP_AUTHORIZATION=make_basic_auth_header(TEST_HOST, TEST_SECRET))
+ HTTP_AUTHORIZATION=make_basic_auth_header(to_http_user(TEST_HOST), TEST_SECRET))
assert response.status_code == 200
# we don't care whether it is nochg or good, but should be one of them:
content = response.content.decode('utf-8')
@@ -122,28 +122,28 @@ def test_nic_update_authorized_ns_unavailable(client):
d.save()
# prepare: we must make sure the real test is not a nochg update
response = client.get(reverse('nic_update') + '?myip=1.2.3.4',
- HTTP_AUTHORIZATION=make_basic_auth_header(TEST_HOST, TEST_SECRET))
+ HTTP_AUTHORIZATION=make_basic_auth_header(to_http_user(TEST_HOST), TEST_SECRET))
assert response.status_code == 200
# now do the real test: ip changed, but we can't update DNS as it is unavailable
response = client.get(reverse('nic_update') + '?myip=4.3.2.1',
- HTTP_AUTHORIZATION=make_basic_auth_header(TEST_HOST, TEST_SECRET))
+ HTTP_AUTHORIZATION=make_basic_auth_header(to_http_user(TEST_HOST), TEST_SECRET))
assert response.status_code == 200
assert response.content == b'dnserr'
def test_nic_update_authorized_myip_v4(client):
response = client.get(reverse('nic_update') + '?myip=4.3.2.1',
- HTTP_AUTHORIZATION=make_basic_auth_header(TEST_HOST, TEST_SECRET))
+ HTTP_AUTHORIZATION=make_basic_auth_header(to_http_user(TEST_HOST), TEST_SECRET))
assert response.status_code == 200
# we don't care whether it is nochg or good, but should be the ip from myip=...:
assert response.content in [b'good 4.3.2.1', b'nochg 4.3.2.1']
response = client.get(reverse('nic_update') + '?myip=1.2.3.4',
- HTTP_AUTHORIZATION=make_basic_auth_header(TEST_HOST, TEST_SECRET))
+ HTTP_AUTHORIZATION=make_basic_auth_header(to_http_user(TEST_HOST), TEST_SECRET))
assert response.status_code == 200
# must be good (was different IP)
assert response.content == b'good 1.2.3.4'
response = client.get(reverse('nic_update') + '?myip=1.2.3.4',
- HTTP_AUTHORIZATION=make_basic_auth_header(TEST_HOST, TEST_SECRET))
+ HTTP_AUTHORIZATION=make_basic_auth_header(to_http_user(TEST_HOST), TEST_SECRET))
assert response.status_code == 200
# must be nochg (was same IP)
assert response.content == b'nochg 1.2.3.4'
@@ -153,17 +153,17 @@ def test_nic_update_authorized_myip_v4(client):
def test_nic_update_authorized_myip_v6(client):
response = client.get(reverse('nic_update') + '?myip=2000::2',
- HTTP_AUTHORIZATION=make_basic_auth_header(TEST_HOST, TEST_SECRET))
+ HTTP_AUTHORIZATION=make_basic_auth_header(to_http_user(TEST_HOST), TEST_SECRET))
assert response.status_code == 200
# we don't care whether it is nochg or good, but should be the ip from myip=...:
assert response.content in [b'good 2000::2', b'nochg 2000::2']
response = client.get(reverse('nic_update') + '?myip=2000::3',
- HTTP_AUTHORIZATION=make_basic_auth_header(TEST_HOST, TEST_SECRET))
+ HTTP_AUTHORIZATION=make_basic_auth_header(to_http_user(TEST_HOST), TEST_SECRET))
assert response.status_code == 200
# must be good (was different IP)
assert response.content == b'good 2000::3'
response = client.get(reverse('nic_update') + '?myip=2000::3',
- HTTP_AUTHORIZATION=make_basic_auth_header(TEST_HOST, TEST_SECRET))
+ HTTP_AUTHORIZATION=make_basic_auth_header(to_http_user(TEST_HOST), TEST_SECRET))
assert response.status_code == 200
# must be nochg (was same IP)
assert response.content == b'nochg 2000::3'
@@ -174,12 +174,12 @@ def test_nic_update_authorized_myip_v6(client):
@pytest.mark.requires_sequential
def test_nic_update_authorized_update_other_services(client):
response = client.get(reverse('nic_update') + '?myip=4.3.2.1',
- HTTP_AUTHORIZATION=make_basic_auth_header(TEST_HOST, TEST_SECRET))
+ HTTP_AUTHORIZATION=make_basic_auth_header(to_http_user(TEST_HOST), TEST_SECRET))
assert response.status_code == 200
# we don't care whether it is nochg or good, but should be the ip from myip=...:
assert response.content in [b'good 4.3.2.1', b'nochg 4.3.2.1']
response = client.get(reverse('nic_update') + '?myip=1.2.3.4',
- HTTP_AUTHORIZATION=make_basic_auth_header(TEST_HOST, TEST_SECRET))
+ HTTP_AUTHORIZATION=make_basic_auth_header(to_http_user(TEST_HOST), TEST_SECRET))
assert response.status_code == 200
# must be good (was different IP)
assert response.content == b'good 1.2.3.4'
@@ -188,7 +188,7 @@ def test_nic_update_authorized_update_other_services(client):
# now check if it updated the other service also:
assert query_ns(TEST_HOST_OTHER, 'A') == '1.2.3.4'
response = client.get(reverse('nic_update') + '?myip=2.3.4.5',
- HTTP_AUTHORIZATION=make_basic_auth_header(TEST_HOST, TEST_SECRET))
+ HTTP_AUTHORIZATION=make_basic_auth_header(to_http_user(TEST_HOST), TEST_SECRET))
assert response.status_code == 200
# must be good (was different IP)
assert response.content == b'good 2.3.4.5'
@@ -199,7 +199,7 @@ def test_nic_update_authorized_update_other_services(client):
def test_nic_update_authorized_badagent(client, settings):
settings.BAD_AGENTS = ['foo', 'bad_agent', 'bar', ]
response = client.get(reverse('nic_update'),
- HTTP_AUTHORIZATION=make_basic_auth_header(TEST_HOST, TEST_SECRET),
+ HTTP_AUTHORIZATION=make_basic_auth_header(to_http_user(TEST_HOST), TEST_SECRET),
HTTP_USER_AGENT='bad_agent')
assert response.status_code == 200
assert response.content == b'badagent'
@@ -209,13 +209,13 @@ def test_nic_update_authorized_badip(client, settings):
settings.BAD_IPS_HOST = IPSet([IPAddress('7.7.7.7'), ])
# normal update, not on blacklist
response = client.get(reverse('nic_update') + '?myip=1.2.3.4',
- HTTP_AUTHORIZATION=make_basic_auth_header(TEST_HOST, TEST_SECRET))
+ HTTP_AUTHORIZATION=make_basic_auth_header(to_http_user(TEST_HOST), TEST_SECRET))
assert response.status_code == 200
content = response.content.decode('utf-8')
assert content.startswith('good ') or content.startswith('nochg ')
# abusive update, ip on blacklist
response = client.get(reverse('nic_update') + '?myip=7.7.7.7',
- HTTP_AUTHORIZATION=make_basic_auth_header(TEST_HOST, TEST_SECRET))
+ HTTP_AUTHORIZATION=make_basic_auth_header(to_http_user(TEST_HOST), TEST_SECRET))
assert response.status_code == 200
assert response.content == b'abuse'
@@ -258,31 +258,31 @@ def test_nic_update_session_foreign_host(client):
def test_nic_delete_authorized_invalid_ip1(client):
response = client.get(reverse('nic_delete') + '?myip=1234',
- HTTP_AUTHORIZATION=make_basic_auth_header(TEST_HOST, TEST_SECRET))
+ HTTP_AUTHORIZATION=make_basic_auth_header(to_http_user(TEST_HOST), TEST_SECRET))
assert response.status_code == 200
assert response.content == b'dnserr'
def test_nic_delete_authorized_invalid_ip2(client):
response = client.get(reverse('nic_delete') + '?myip=%C3%A4%C3%BC%C3%B6',
- HTTP_AUTHORIZATION=make_basic_auth_header(TEST_HOST, TEST_SECRET))
+ HTTP_AUTHORIZATION=make_basic_auth_header(to_http_user(TEST_HOST), TEST_SECRET))
assert response.status_code == 200
assert response.content == b'dnserr'
def test_nic_delete_authorized(client):
response = client.get(reverse('nic_update') + '?myip=%s' % ('1.2.3.4', ),
- HTTP_AUTHORIZATION=make_basic_auth_header(TEST_HOST, TEST_SECRET))
+ HTTP_AUTHORIZATION=make_basic_auth_header(to_http_user(TEST_HOST), TEST_SECRET))
assert response.status_code == 200
response = client.get(reverse('nic_update') + '?myip=%s' % ('::1', ),
- HTTP_AUTHORIZATION=make_basic_auth_header(TEST_HOST, TEST_SECRET))
+ HTTP_AUTHORIZATION=make_basic_auth_header(to_http_user(TEST_HOST), TEST_SECRET))
assert response.status_code == 200
response = client.get(reverse('nic_delete') + '?myip=%s' % ('0.0.0.0', ),
- HTTP_AUTHORIZATION=make_basic_auth_header(TEST_HOST, TEST_SECRET))
+ HTTP_AUTHORIZATION=make_basic_auth_header(to_http_user(TEST_HOST), TEST_SECRET))
assert response.status_code == 200
assert response.content == b'deleted A'
response = client.get(reverse('nic_delete') + '?myip=%s' % ('::', ),
- HTTP_AUTHORIZATION=make_basic_auth_header(TEST_HOST, TEST_SECRET))
+ HTTP_AUTHORIZATION=make_basic_auth_header(to_http_user(TEST_HOST), TEST_SECRET))
assert response.status_code == 200
assert response.content == b'deleted AAAA'
From b3d6c6c44a909549183faa01edf1f8b57158f5fd Mon Sep 17 00:00:00 2001
From: Brice Gros
Date: Tue, 21 Jan 2020 16:41:10 +0100
Subject: [PATCH 09/15] fix code assuming string but getting FQDN instances
---
conftest.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/conftest.py b/conftest.py
index 58729153..2b94ba4a 100644
--- a/conftest.py
+++ b/conftest.py
@@ -41,7 +41,7 @@
from nsupdate.main.dnstools import update_ns, FQDN
def to_http_user(hostname):
- return hostname[:_HOST_HTTP_USER_MAX_LENGTH].zfill(_HOST_HTTP_USER_MAX_LENGTH)
+ return str(hostname[:_HOST_HTTP_USER_MAX_LENGTH]).zfill(_HOST_HTTP_USER_MAX_LENGTH)
@pytest.yield_fixture(scope="function")
def ddns_hostname():
From df5419405790d39b79c73c211870fb48a2e0b6ba Mon Sep 17 00:00:00 2001
From: Brice Gros
Date: Tue, 21 Jan 2020 16:41:49 +0100
Subject: [PATCH 10/15] fix code assuming string but getting FQDN instances
---
conftest.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/conftest.py b/conftest.py
index 2b94ba4a..b64d1912 100644
--- a/conftest.py
+++ b/conftest.py
@@ -41,7 +41,7 @@
from nsupdate.main.dnstools import update_ns, FQDN
def to_http_user(hostname):
- return str(hostname[:_HOST_HTTP_USER_MAX_LENGTH]).zfill(_HOST_HTTP_USER_MAX_LENGTH)
+ return str(hostname)[:_HOST_HTTP_USER_MAX_LENGTH].zfill(_HOST_HTTP_USER_MAX_LENGTH)
@pytest.yield_fixture(scope="function")
def ddns_hostname():
From 8b61d7935412df382e73d90252d77772d180e483 Mon Sep 17 00:00:00 2001
From: Brice Gros
Date: Tue, 21 Jan 2020 16:49:00 +0100
Subject: [PATCH 11/15] fix http_user for instances in conftest.py
---
conftest.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/conftest.py b/conftest.py
index b64d1912..bbe66a8b 100644
--- a/conftest.py
+++ b/conftest.py
@@ -99,10 +99,10 @@ def db_init(db): # note: db is a predefined fixture and required here to have t
)
# a Host for api / session update tests
hostname = TEST_HOST.host
- h = Host(name=hostname, domain=dt, created_by=u, netmask_ipv4=29, netmask_ipv6=64, http_user=to_http_user(hostname))
+ h = Host(name=hostname, domain=dt, created_by=u, netmask_ipv4=29, netmask_ipv6=64, http_user=to_http_user(TEST_HOST))
h.generate_secret(secret=TEST_SECRET)
hostname2 = TEST_HOST2.host
- h2 = Host(name=hostname2, domain=dt, created_by=u2, netmask_ipv4=29, netmask_ipv6=64, http_user=to_http_user(hostname2))
+ h2 = Host(name=hostname2, domain=dt, created_by=u2, netmask_ipv4=29, netmask_ipv6=64, http_user=to_http_user(TEST_HOST2))
h2.generate_secret(secret=TEST_SECRET2)
# "update other service" ddns_client feature
From 0b56342ac65ae68fcb399ef40e5d9187eb4d6fd1 Mon Sep 17 00:00:00 2001
From: Brice Gros
Date: Tue, 21 Jan 2020 17:03:13 +0100
Subject: [PATCH 12/15] fix coding style
---
conftest.py | 8 ++++++--
src/nsupdate/main/models.py | 8 ++++++--
2 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/conftest.py b/conftest.py
index bbe66a8b..c929af57 100644
--- a/conftest.py
+++ b/conftest.py
@@ -40,9 +40,11 @@
from nsupdate.main.dnstools import update_ns, FQDN
+
def to_http_user(hostname):
return str(hostname)[:_HOST_HTTP_USER_MAX_LENGTH].zfill(_HOST_HTTP_USER_MAX_LENGTH)
+
@pytest.yield_fixture(scope="function")
def ddns_hostname():
"""
@@ -99,10 +101,12 @@ def db_init(db): # note: db is a predefined fixture and required here to have t
)
# a Host for api / session update tests
hostname = TEST_HOST.host
- h = Host(name=hostname, domain=dt, created_by=u, netmask_ipv4=29, netmask_ipv6=64, http_user=to_http_user(TEST_HOST))
+ h = Host(name=hostname, domain=dt, created_by=u, netmask_ipv4=29, netmask_ipv6=64,
+ http_user=to_http_user(TEST_HOST))
h.generate_secret(secret=TEST_SECRET)
hostname2 = TEST_HOST2.host
- h2 = Host(name=hostname2, domain=dt, created_by=u2, netmask_ipv4=29, netmask_ipv6=64, http_user=to_http_user(TEST_HOST2))
+ h2 = Host(name=hostname2, domain=dt, created_by=u2, netmask_ipv4=29, netmask_ipv6=64,
+ http_user=to_http_user(TEST_HOST2))
h2.generate_secret(secret=TEST_SECRET2)
# "update other service" ddns_client feature
diff --git a/src/nsupdate/main/models.py b/src/nsupdate/main/models.py
index 6976343d..02f071de 100644
--- a/src/nsupdate/main/models.py
+++ b/src/nsupdate/main/models.py
@@ -155,10 +155,14 @@ class Meta:
verbose_name_plural = _('domains')
ordering = ('name',)
-_HOST_HTTP_USER_MAX_LENGTH=30 # limit comes from an external application not accepting longer username must be same than in Host.max_length
+
+# limit comes from an external application not accepting longer username must be same than in Host.max_length
+_HOST_HTTP_USER_MAX_LENGTH = 30
+
+
def _http_user_generator():
dt = datetime.utcnow().strftime('%Y%m%d%H%m%S%f')
- maxrange = pow(10, _HOST_HTTP_USER_MAX_LENGTH-len(dt))
+ maxrange = pow(10, _HOST_HTTP_USER_MAX_LENGTH - len(dt))
randvalue = random.randrange(0, maxrange)
username = '{randvalue}{dt}'.format(randvalue=randvalue, dt=dt).zfill(_HOST_HTTP_USER_MAX_LENGTH)
return username
From 91effe2d426244ef354c5a986e20d6f073c16c38 Mon Sep 17 00:00:00 2001
From: Brice Gros
Date: Tue, 21 Jan 2020 17:04:10 +0100
Subject: [PATCH 13/15] remove irrelevant tests since username does not require
to be a fqdn due to Host.http_user field
---
src/nsupdate/api/_tests/test_api.py | 7 -------
1 file changed, 7 deletions(-)
diff --git a/src/nsupdate/api/_tests/test_api.py b/src/nsupdate/api/_tests/test_api.py
index 7c432892..e63bd3a4 100644
--- a/src/nsupdate/api/_tests/test_api.py
+++ b/src/nsupdate/api/_tests/test_api.py
@@ -86,13 +86,6 @@ def test_nic_update_authorized_not_fqdn_hostname(client):
assert response.content == b'notfqdn'
-def test_nic_update_authorized_not_fqdn_username(client):
- response = client.get(reverse('nic_update'),
- HTTP_AUTHORIZATION=make_basic_auth_header('test', TEST_SECRET))
- assert response.status_code == 200
- assert response.content == b'notfqdn'
-
-
def test_nic_update_authorized_invalid_ip1(client):
response = client.get(reverse('nic_update') + '?myip=1234',
HTTP_AUTHORIZATION=make_basic_auth_header(to_http_user(TEST_HOST), TEST_SECRET))
From 08f55175bc8832e946e9b661f39e0749b8921491 Mon Sep 17 00:00:00 2001
From: Brice Gros
Date: Tue, 22 Oct 2024 11:31:49 +0200
Subject: [PATCH 14/15] Fix typo
---
src/nsupdate/main/models.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/nsupdate/main/models.py b/src/nsupdate/main/models.py
index 6ef8e4c1..fbe3ae45 100644
--- a/src/nsupdate/main/models.py
+++ b/src/nsupdate/main/models.py
@@ -301,7 +301,7 @@ def get_by_http_user(cls, username, **kwargs):
return None
except Host.MultipleObjectsReturned:
# should not happen, see Host.http_user should have unique=True
- raise ValueError("get_by_http_user(%s) found more than 1 host" % fqdn)
+ raise ValueError("get_by_http_user(%s) found more than 1 host" % username)
else:
return host
From 78cea87503f292ecee174162e66c606fcdd3ee30 Mon Sep 17 00:00:00 2001
From: Brice Gros
Date: Tue, 22 Oct 2024 11:46:47 +0200
Subject: [PATCH 15/15] Lint
---
conftest.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/conftest.py b/conftest.py
index 587e2ab9..8fae5ab8 100644
--- a/conftest.py
+++ b/conftest.py
@@ -44,6 +44,7 @@
def to_http_user(hostname):
return str(hostname)[:_HOST_HTTP_USER_MAX_LENGTH].zfill(_HOST_HTTP_USER_MAX_LENGTH)
+
@pytest.fixture(scope="function")
def ddns_hostname():
"""