From ab5bfb21308f8b6c93badaa302a8db4e7638c2a9 Mon Sep 17 00:00:00 2001 From: Ian Lin <4056670+ianlini@users.noreply.github.com> Date: Sun, 3 Dec 2023 15:41:15 +0800 Subject: [PATCH] Record issue datetime for keys (#15) --- README.rst | 2 +- cspell.json | 2 + poetry.lock | 190 +++++++++++++----- pyproject.toml | 2 +- src/wg_wizard/cli.py | 4 +- src/wg_wizard/core.py | 81 +++++--- src/wg_wizard/utils.py | 23 +-- src/wg_wizard/wg_quick.py | 22 +- tests/conftest.py | 15 ++ .../expected_wg_quick_config/wg0_None | 85 ++++++++ .../expected_wg_quick_config/wg0_client_0 | 50 +++++ .../default_with_one_client/wg0_secret.json | 12 +- tests/test_cli.py | 38 ++++ tests/test_core.py | 39 +++- 14 files changed, 455 insertions(+), 110 deletions(-) create mode 100644 tests/conftest.py create mode 100644 tests/data/default_with_one_client/expected_wg_quick_config/wg0_None create mode 100644 tests/data/default_with_one_client/expected_wg_quick_config/wg0_client_0 create mode 100644 tests/test_cli.py diff --git a/README.rst b/README.rst index 03ae5df..e71b617 100644 --- a/README.rst +++ b/README.rst @@ -78,7 +78,7 @@ Follow the instruction to create the config. Example output: Interface name for WireGuard [wg0]: Interface.ListenPort of the relay server [51820]: Interface.Address of the relay server [192.168.10.1/24]: - The default endpoint in clients' Peer.Endpoint configs (e.g., example.com:51280): example.com + The default endpoint in clients' Peer.Endpoint configs (e.g., example.com:51820): example.com If you want to allow the clients to access the internet via the relay server, you must provide the interface name you want to forward the internet traffic to. It's usually eth0 or wlan0. You can check it by executing `ip addr`. If you provide an interface name {interface}, the following rules will be added: - iptables -A FORWARD -i %i -o {interface} -j ACCEPT - iptables -A FORWARD -i {interface} -o %i -j ACCEPT diff --git a/cspell.json b/cspell.json index d8e71ab..f25efea 100644 --- a/cspell.json +++ b/cspell.json @@ -4,7 +4,9 @@ "python" ], "words": [ + "addoption", "bistiming", + "capsys", "distro", "genkey", "genpsk", diff --git a/poetry.lock b/poetry.lock index 5f08597..9fb1268 100644 --- a/poetry.lock +++ b/poetry.lock @@ -11,6 +11,17 @@ files = [ {file = "alabaster-0.7.12.tar.gz", hash = "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"}, ] +[[package]] +name = "annotated-types" +version = "0.6.0" +description = "Reusable constraint types to use with typing.Annotated" +optional = false +python-versions = ">=3.8" +files = [ + {file = "annotated_types-0.6.0-py3-none-any.whl", hash = "sha256:0641064de18ba7a25dee8f96403ebc39113d0cb953a01429249d5c7564666a43"}, + {file = "annotated_types-0.6.0.tar.gz", hash = "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d"}, +] + [[package]] name = "appdirs" version = "1.4.4" @@ -931,54 +942,139 @@ files = [ [[package]] name = "pydantic" -version = "1.9.2" -description = "Data validation and settings management using python type hints" +version = "2.5.2" +description = "Data validation using Python type hints" optional = false -python-versions = ">=3.6.1" +python-versions = ">=3.7" files = [ - {file = "pydantic-1.9.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9c9e04a6cdb7a363d7cb3ccf0efea51e0abb48e180c0d31dca8d247967d85c6e"}, - {file = "pydantic-1.9.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fafe841be1103f340a24977f61dee76172e4ae5f647ab9e7fd1e1fca51524f08"}, - {file = "pydantic-1.9.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afacf6d2a41ed91fc631bade88b1d319c51ab5418870802cedb590b709c5ae3c"}, - {file = "pydantic-1.9.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ee0d69b2a5b341fc7927e92cae7ddcfd95e624dfc4870b32a85568bd65e6131"}, - {file = "pydantic-1.9.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ff68fc85355532ea77559ede81f35fff79a6a5543477e168ab3a381887caea76"}, - {file = "pydantic-1.9.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c0f5e142ef8217019e3eef6ae1b6b55f09a7a15972958d44fbd228214cede567"}, - {file = "pydantic-1.9.2-cp310-cp310-win_amd64.whl", hash = "sha256:615661bfc37e82ac677543704437ff737418e4ea04bef9cf11c6d27346606044"}, - {file = "pydantic-1.9.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:328558c9f2eed77bd8fffad3cef39dbbe3edc7044517f4625a769d45d4cf7555"}, - {file = "pydantic-1.9.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bd446bdb7755c3a94e56d7bdfd3ee92396070efa8ef3a34fab9579fe6aa1d84"}, - {file = "pydantic-1.9.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e0b214e57623a535936005797567231a12d0da0c29711eb3514bc2b3cd008d0f"}, - {file = "pydantic-1.9.2-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:d8ce3fb0841763a89322ea0432f1f59a2d3feae07a63ea2c958b2315e1ae8adb"}, - {file = "pydantic-1.9.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:b34ba24f3e2d0b39b43f0ca62008f7ba962cff51efa56e64ee25c4af6eed987b"}, - {file = "pydantic-1.9.2-cp36-cp36m-win_amd64.whl", hash = "sha256:84d76ecc908d917f4684b354a39fd885d69dd0491be175f3465fe4b59811c001"}, - {file = "pydantic-1.9.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4de71c718c9756d679420c69f216776c2e977459f77e8f679a4a961dc7304a56"}, - {file = "pydantic-1.9.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5803ad846cdd1ed0d97eb00292b870c29c1f03732a010e66908ff48a762f20e4"}, - {file = "pydantic-1.9.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a8c5360a0297a713b4123608a7909e6869e1b56d0e96eb0d792c27585d40757f"}, - {file = "pydantic-1.9.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:cdb4272678db803ddf94caa4f94f8672e9a46bae4a44f167095e4d06fec12979"}, - {file = "pydantic-1.9.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:19b5686387ea0d1ea52ecc4cffb71abb21702c5e5b2ac626fd4dbaa0834aa49d"}, - {file = "pydantic-1.9.2-cp37-cp37m-win_amd64.whl", hash = "sha256:32e0b4fb13ad4db4058a7c3c80e2569adbd810c25e6ca3bbd8b2a9cc2cc871d7"}, - {file = "pydantic-1.9.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:91089b2e281713f3893cd01d8e576771cd5bfdfbff5d0ed95969f47ef6d676c3"}, - {file = "pydantic-1.9.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e631c70c9280e3129f071635b81207cad85e6c08e253539467e4ead0e5b219aa"}, - {file = "pydantic-1.9.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b3946f87e5cef3ba2e7bd3a4eb5a20385fe36521d6cc1ebf3c08a6697c6cfb3"}, - {file = "pydantic-1.9.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5565a49effe38d51882cb7bac18bda013cdb34d80ac336428e8908f0b72499b0"}, - {file = "pydantic-1.9.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:bd67cb2c2d9602ad159389c29e4ca964b86fa2f35c2faef54c3eb28b4efd36c8"}, - {file = "pydantic-1.9.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:4aafd4e55e8ad5bd1b19572ea2df546ccace7945853832bb99422a79c70ce9b8"}, - {file = "pydantic-1.9.2-cp38-cp38-win_amd64.whl", hash = "sha256:d70916235d478404a3fa8c997b003b5f33aeac4686ac1baa767234a0f8ac2326"}, - {file = "pydantic-1.9.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f0ca86b525264daa5f6b192f216a0d1e860b7383e3da1c65a1908f9c02f42801"}, - {file = "pydantic-1.9.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1061c6ee6204f4f5a27133126854948e3b3d51fcc16ead2e5d04378c199b2f44"}, - {file = "pydantic-1.9.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e78578f0c7481c850d1c969aca9a65405887003484d24f6110458fb02cca7747"}, - {file = "pydantic-1.9.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5da164119602212a3fe7e3bc08911a89db4710ae51444b4224c2382fd09ad453"}, - {file = "pydantic-1.9.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7ead3cd020d526f75b4188e0a8d71c0dbbe1b4b6b5dc0ea775a93aca16256aeb"}, - {file = "pydantic-1.9.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7d0f183b305629765910eaad707800d2f47c6ac5bcfb8c6397abdc30b69eeb15"}, - {file = "pydantic-1.9.2-cp39-cp39-win_amd64.whl", hash = "sha256:f1a68f4f65a9ee64b6ccccb5bf7e17db07caebd2730109cb8a95863cfa9c4e55"}, - {file = "pydantic-1.9.2-py3-none-any.whl", hash = "sha256:78a4d6bdfd116a559aeec9a4cfe77dda62acc6233f8b56a716edad2651023e5e"}, - {file = "pydantic-1.9.2.tar.gz", hash = "sha256:8cb0bc509bfb71305d7a59d00163d5f9fc4530f0881ea32c74ff4f74c85f3d3d"}, + {file = "pydantic-2.5.2-py3-none-any.whl", hash = "sha256:80c50fb8e3dcecfddae1adbcc00ec5822918490c99ab31f6cf6140ca1c1429f0"}, + {file = "pydantic-2.5.2.tar.gz", hash = "sha256:ff177ba64c6faf73d7afa2e8cad38fd456c0dbe01c9954e71038001cd15a6edd"}, ] [package.dependencies] -typing-extensions = ">=3.7.4.3" +annotated-types = ">=0.4.0" +pydantic-core = "2.14.5" +typing-extensions = ">=4.6.1" [package.extras] -dotenv = ["python-dotenv (>=0.10.4)"] -email = ["email-validator (>=1.0.3)"] +email = ["email-validator (>=2.0.0)"] + +[[package]] +name = "pydantic-core" +version = "2.14.5" +description = "" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pydantic_core-2.14.5-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:7e88f5696153dc516ba6e79f82cc4747e87027205f0e02390c21f7cb3bd8abfd"}, + {file = "pydantic_core-2.14.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4641e8ad4efb697f38a9b64ca0523b557c7931c5f84e0fd377a9a3b05121f0de"}, + {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:774de879d212db5ce02dfbf5b0da9a0ea386aeba12b0b95674a4ce0593df3d07"}, + {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ebb4e035e28f49b6f1a7032920bb9a0c064aedbbabe52c543343d39341a5b2a3"}, + {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b53e9ad053cd064f7e473a5f29b37fc4cc9dc6d35f341e6afc0155ea257fc911"}, + {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8aa1768c151cf562a9992462239dfc356b3d1037cc5a3ac829bb7f3bda7cc1f9"}, + {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eac5c82fc632c599f4639a5886f96867ffced74458c7db61bc9a66ccb8ee3113"}, + {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d2ae91f50ccc5810b2f1b6b858257c9ad2e08da70bf890dee02de1775a387c66"}, + {file = "pydantic_core-2.14.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6b9ff467ffbab9110e80e8c8de3bcfce8e8b0fd5661ac44a09ae5901668ba997"}, + {file = "pydantic_core-2.14.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:61ea96a78378e3bd5a0be99b0e5ed00057b71f66115f5404d0dae4819f495093"}, + {file = "pydantic_core-2.14.5-cp310-none-win32.whl", hash = "sha256:bb4c2eda937a5e74c38a41b33d8c77220380a388d689bcdb9b187cf6224c9720"}, + {file = "pydantic_core-2.14.5-cp310-none-win_amd64.whl", hash = "sha256:b7851992faf25eac90bfcb7bfd19e1f5ffa00afd57daec8a0042e63c74a4551b"}, + {file = "pydantic_core-2.14.5-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:4e40f2bd0d57dac3feb3a3aed50f17d83436c9e6b09b16af271b6230a2915459"}, + {file = "pydantic_core-2.14.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ab1cdb0f14dc161ebc268c09db04d2c9e6f70027f3b42446fa11c153521c0e88"}, + {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aae7ea3a1c5bb40c93cad361b3e869b180ac174656120c42b9fadebf685d121b"}, + {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:60b7607753ba62cf0739177913b858140f11b8af72f22860c28eabb2f0a61937"}, + {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2248485b0322c75aee7565d95ad0e16f1c67403a470d02f94da7344184be770f"}, + {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:823fcc638f67035137a5cd3f1584a4542d35a951c3cc68c6ead1df7dac825c26"}, + {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96581cfefa9123accc465a5fd0cc833ac4d75d55cc30b633b402e00e7ced00a6"}, + {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a33324437018bf6ba1bb0f921788788641439e0ed654b233285b9c69704c27b4"}, + {file = "pydantic_core-2.14.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9bd18fee0923ca10f9a3ff67d4851c9d3e22b7bc63d1eddc12f439f436f2aada"}, + {file = "pydantic_core-2.14.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:853a2295c00f1d4429db4c0fb9475958543ee80cfd310814b5c0ef502de24dda"}, + {file = "pydantic_core-2.14.5-cp311-none-win32.whl", hash = "sha256:cb774298da62aea5c80a89bd58c40205ab4c2abf4834453b5de207d59d2e1651"}, + {file = "pydantic_core-2.14.5-cp311-none-win_amd64.whl", hash = "sha256:e87fc540c6cac7f29ede02e0f989d4233f88ad439c5cdee56f693cc9c1c78077"}, + {file = "pydantic_core-2.14.5-cp311-none-win_arm64.whl", hash = "sha256:57d52fa717ff445cb0a5ab5237db502e6be50809b43a596fb569630c665abddf"}, + {file = "pydantic_core-2.14.5-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:e60f112ac88db9261ad3a52032ea46388378034f3279c643499edb982536a093"}, + {file = "pydantic_core-2.14.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6e227c40c02fd873c2a73a98c1280c10315cbebe26734c196ef4514776120aeb"}, + {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0cbc7fff06a90bbd875cc201f94ef0ee3929dfbd5c55a06674b60857b8b85ed"}, + {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:103ef8d5b58596a731b690112819501ba1db7a36f4ee99f7892c40da02c3e189"}, + {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c949f04ecad823f81b1ba94e7d189d9dfb81edbb94ed3f8acfce41e682e48cef"}, + {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c1452a1acdf914d194159439eb21e56b89aa903f2e1c65c60b9d874f9b950e5d"}, + {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb4679d4c2b089e5ef89756bc73e1926745e995d76e11925e3e96a76d5fa51fc"}, + {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cf9d3fe53b1ee360e2421be95e62ca9b3296bf3f2fb2d3b83ca49ad3f925835e"}, + {file = "pydantic_core-2.14.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:70f4b4851dbb500129681d04cc955be2a90b2248d69273a787dda120d5cf1f69"}, + {file = "pydantic_core-2.14.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:59986de5710ad9613ff61dd9b02bdd2f615f1a7052304b79cc8fa2eb4e336d2d"}, + {file = "pydantic_core-2.14.5-cp312-none-win32.whl", hash = "sha256:699156034181e2ce106c89ddb4b6504c30db8caa86e0c30de47b3e0654543260"}, + {file = "pydantic_core-2.14.5-cp312-none-win_amd64.whl", hash = "sha256:5baab5455c7a538ac7e8bf1feec4278a66436197592a9bed538160a2e7d11e36"}, + {file = "pydantic_core-2.14.5-cp312-none-win_arm64.whl", hash = "sha256:e47e9a08bcc04d20975b6434cc50bf82665fbc751bcce739d04a3120428f3e27"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:af36f36538418f3806048f3b242a1777e2540ff9efaa667c27da63d2749dbce0"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:45e95333b8418ded64745f14574aa9bfc212cb4fbeed7a687b0c6e53b5e188cd"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e47a76848f92529879ecfc417ff88a2806438f57be4a6a8bf2961e8f9ca9ec7"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d81e6987b27bc7d101c8597e1cd2bcaa2fee5e8e0f356735c7ed34368c471550"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:34708cc82c330e303f4ce87758828ef6e457681b58ce0e921b6e97937dd1e2a3"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:652c1988019752138b974c28f43751528116bcceadad85f33a258869e641d753"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e4d090e73e0725b2904fdbdd8d73b8802ddd691ef9254577b708d413bf3006e"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5c7d5b5005f177764e96bd584d7bf28d6e26e96f2a541fdddb934c486e36fd59"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:a71891847f0a73b1b9eb86d089baee301477abef45f7eaf303495cd1473613e4"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a717aef6971208f0851a2420b075338e33083111d92041157bbe0e2713b37325"}, + {file = "pydantic_core-2.14.5-cp37-none-win32.whl", hash = "sha256:de790a3b5aa2124b8b78ae5faa033937a72da8efe74b9231698b5a1dd9be3405"}, + {file = "pydantic_core-2.14.5-cp37-none-win_amd64.whl", hash = "sha256:6c327e9cd849b564b234da821236e6bcbe4f359a42ee05050dc79d8ed2a91588"}, + {file = "pydantic_core-2.14.5-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:ef98ca7d5995a82f43ec0ab39c4caf6a9b994cb0b53648ff61716370eadc43cf"}, + {file = "pydantic_core-2.14.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c6eae413494a1c3f89055da7a5515f32e05ebc1a234c27674a6956755fb2236f"}, + {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcf4e6d85614f7a4956c2de5a56531f44efb973d2fe4a444d7251df5d5c4dcfd"}, + {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6637560562134b0e17de333d18e69e312e0458ee4455bdad12c37100b7cad706"}, + {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:77fa384d8e118b3077cccfcaf91bf83c31fe4dc850b5e6ee3dc14dc3d61bdba1"}, + {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16e29bad40bcf97aac682a58861249ca9dcc57c3f6be22f506501833ddb8939c"}, + {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:531f4b4252fac6ca476fbe0e6f60f16f5b65d3e6b583bc4d87645e4e5ddde331"}, + {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:074f3d86f081ce61414d2dc44901f4f83617329c6f3ab49d2bc6c96948b2c26b"}, + {file = "pydantic_core-2.14.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c2adbe22ab4babbca99c75c5d07aaf74f43c3195384ec07ccbd2f9e3bddaecec"}, + {file = "pydantic_core-2.14.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0f6116a558fd06d1b7c2902d1c4cf64a5bd49d67c3540e61eccca93f41418124"}, + {file = "pydantic_core-2.14.5-cp38-none-win32.whl", hash = "sha256:fe0a5a1025eb797752136ac8b4fa21aa891e3d74fd340f864ff982d649691867"}, + {file = "pydantic_core-2.14.5-cp38-none-win_amd64.whl", hash = "sha256:079206491c435b60778cf2b0ee5fd645e61ffd6e70c47806c9ed51fc75af078d"}, + {file = "pydantic_core-2.14.5-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:a6a16f4a527aae4f49c875da3cdc9508ac7eef26e7977952608610104244e1b7"}, + {file = "pydantic_core-2.14.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:abf058be9517dc877227ec3223f0300034bd0e9f53aebd63cf4456c8cb1e0863"}, + {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:49b08aae5013640a3bfa25a8eebbd95638ec3f4b2eaf6ed82cf0c7047133f03b"}, + {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c2d97e906b4ff36eb464d52a3bc7d720bd6261f64bc4bcdbcd2c557c02081ed2"}, + {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3128e0bbc8c091ec4375a1828d6118bc20404883169ac95ffa8d983b293611e6"}, + {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88e74ab0cdd84ad0614e2750f903bb0d610cc8af2cc17f72c28163acfcf372a4"}, + {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c339dabd8ee15f8259ee0f202679b6324926e5bc9e9a40bf981ce77c038553db"}, + {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3387277f1bf659caf1724e1afe8ee7dbc9952a82d90f858ebb931880216ea955"}, + {file = "pydantic_core-2.14.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ba6b6b3846cfc10fdb4c971980a954e49d447cd215ed5a77ec8190bc93dd7bc5"}, + {file = "pydantic_core-2.14.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ca61d858e4107ce5e1330a74724fe757fc7135190eb5ce5c9d0191729f033209"}, + {file = "pydantic_core-2.14.5-cp39-none-win32.whl", hash = "sha256:ec1e72d6412f7126eb7b2e3bfca42b15e6e389e1bc88ea0069d0cc1742f477c6"}, + {file = "pydantic_core-2.14.5-cp39-none-win_amd64.whl", hash = "sha256:c0b97ec434041827935044bbbe52b03d6018c2897349670ff8fe11ed24d1d4ab"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:79e0a2cdbdc7af3f4aee3210b1172ab53d7ddb6a2d8c24119b5706e622b346d0"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:678265f7b14e138d9a541ddabbe033012a2953315739f8cfa6d754cc8063e8ca"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95b15e855ae44f0c6341ceb74df61b606e11f1087e87dcb7482377374aac6abe"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:09b0e985fbaf13e6b06a56d21694d12ebca6ce5414b9211edf6f17738d82b0f8"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3ad873900297bb36e4b6b3f7029d88ff9829ecdc15d5cf20161775ce12306f8a"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:2d0ae0d8670164e10accbeb31d5ad45adb71292032d0fdb9079912907f0085f4"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:d37f8ec982ead9ba0a22a996129594938138a1503237b87318392a48882d50b7"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:35613015f0ba7e14c29ac6c2483a657ec740e5ac5758d993fdd5870b07a61d8b"}, + {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-macosx_10_7_x86_64.whl", hash = "sha256:ab4ea451082e684198636565224bbb179575efc1658c48281b2c866bfd4ddf04"}, + {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ce601907e99ea5b4adb807ded3570ea62186b17f88e271569144e8cca4409c7"}, + {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb2ed8b3fe4bf4506d6dab3b93b83bbc22237e230cba03866d561c3577517d18"}, + {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:70f947628e074bb2526ba1b151cee10e4c3b9670af4dbb4d73bc8a89445916b5"}, + {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:4bc536201426451f06f044dfbf341c09f540b4ebdb9fd8d2c6164d733de5e634"}, + {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f4791cf0f8c3104ac668797d8c514afb3431bc3305f5638add0ba1a5a37e0d88"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:038c9f763e650712b899f983076ce783175397c848da04985658e7628cbe873b"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:27548e16c79702f1e03f5628589c6057c9ae17c95b4c449de3c66b589ead0520"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c97bee68898f3f4344eb02fec316db93d9700fb1e6a5b760ffa20d71d9a46ce3"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9b759b77f5337b4ea024f03abc6464c9f35d9718de01cfe6bae9f2e139c397e"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:439c9afe34638ace43a49bf72d201e0ffc1a800295bed8420c2a9ca8d5e3dbb3"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:ba39688799094c75ea8a16a6b544eb57b5b0f3328697084f3f2790892510d144"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ccd4d5702bb90b84df13bd491be8d900b92016c5a455b7e14630ad7449eb03f8"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:81982d78a45d1e5396819bbb4ece1fadfe5f079335dd28c4ab3427cd95389944"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:7f8210297b04e53bc3da35db08b7302a6a1f4889c79173af69b72ec9754796b8"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:8c8a8812fe6f43a3a5b054af6ac2d7b8605c7bcab2804a8a7d68b53f3cd86e00"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:206ed23aecd67c71daf5c02c3cd19c0501b01ef3cbf7782db9e4e051426b3d0d"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c2027d05c8aebe61d898d4cffd774840a9cb82ed356ba47a90d99ad768f39789"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:40180930807ce806aa71eda5a5a5447abb6b6a3c0b4b3b1b1962651906484d68"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:615a0a4bff11c45eb3c1996ceed5bdaa2f7b432425253a7c2eed33bb86d80abc"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f5e412d717366e0677ef767eac93566582518fe8be923361a5c204c1a62eaafe"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:513b07e99c0a267b1d954243845d8a833758a6726a3b5d8948306e3fe14675e3"}, + {file = "pydantic_core-2.14.5.tar.gz", hash = "sha256:6d30226dfc816dd0fdf120cae611dd2215117e4f9b124af8c60ab9093b6e8e71"}, +] + +[package.dependencies] +typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" [[package]] name = "pydocstyle" @@ -1484,13 +1580,13 @@ test = ["pre-commit", "pytest"] [[package]] name = "typing-extensions" -version = "4.3.0" -description = "Backported and Experimental Type Hints for Python 3.7+" +version = "4.8.0" +description = "Backported and Experimental Type Hints for Python 3.8+" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.3.0-py3-none-any.whl", hash = "sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02"}, - {file = "typing_extensions-4.3.0.tar.gz", hash = "sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6"}, + {file = "typing_extensions-4.8.0-py3-none-any.whl", hash = "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0"}, + {file = "typing_extensions-4.8.0.tar.gz", hash = "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"}, ] [[package]] @@ -1543,4 +1639,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "f47615023e05b623d7c904d9794c60e68c0ea9a9d8e0e0039c0ea3649e98ad48" +content-hash = "a7aa5fb3147609aea269c4c9c6f85cedcbb4bfa4e21cd172bce2168016d9ebb8" diff --git a/pyproject.toml b/pyproject.toml index ddfada3..e73febb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,7 +17,7 @@ classifiers = [ python = "^3.10" click = "^8.1.3" "ruamel.yaml" = "^0.17.21" -pydantic = "^1.9.2" +pydantic = "^2.0.0" qrcode = "^7.3.1" [tool.poetry.group.linter.dependencies] diff --git a/src/wg_wizard/cli.py b/src/wg_wizard/cli.py index cb5ee66..dead613 100644 --- a/src/wg_wizard/cli.py +++ b/src/wg_wizard/cli.py @@ -56,9 +56,9 @@ def main(): @option( "--default-endpoint", "-e", - prompt="The default endpoint in clients' Peer.Endpoint configs (e.g., example.com:51280)", + prompt="The default endpoint in clients' Peer.Endpoint configs (e.g., example.com:51820)", help=""" - The default endpoint in clients' Peer.Endpoint configs (e.g., example.com:51280). + The default endpoint in clients' Peer.Endpoint configs (e.g., example.com:51820). If the port is not provided, it will be added automatically according to the listen_port. The endpoint can also be overridden in peer configs. """, diff --git a/src/wg_wizard/core.py b/src/wg_wizard/core.py index 84936ec..5a9f9dd 100644 --- a/src/wg_wizard/core.py +++ b/src/wg_wizard/core.py @@ -1,6 +1,7 @@ +import datetime from ipaddress import ip_interface from pathlib import Path -from typing import Literal, Optional +from typing import Annotated, Literal, Optional import json import logging @@ -9,9 +10,10 @@ Field, IPvAnyInterface, IPvAnyAddress, - constr, + StringConstraints, SecretStr, PrivateAttr, + field_serializer, ) from ruamel.yaml import YAML @@ -30,40 +32,45 @@ class WgWizardPeerConfig(StrictModel): - listen_port: Optional[int] - fw_mark: Optional[Literal["off"] | int] - addresses: list[IPvAnyInterface] = Field(min_items=1) + listen_port: Optional[int] = None + fw_mark: Optional[Literal["off"] | int] = None + addresses: list[IPvAnyInterface] = Field(min_length=1) dns_addresses: list[IPvAnyAddress] = Field(default_factory=list) - mtu: Optional[int] - table: Optional[str] + mtu: Optional[int] = None + table: Optional[str] = None pre_up: list[str] = Field(default_factory=list) post_up: list[str] = Field(default_factory=list) pre_down: list[str] = Field(default_factory=list) post_down: list[str] = Field(default_factory=list) - server_allowed_ips: list[IPvAnyInterface] = Field(min_items=1) - server_endpoint: Optional[constr(regex=r".+:\d+")] # noqa: F722 - server_persistent_keepalive: Optional[Literal["off"] | int] - client_allowed_ips: list[IPvAnyInterface] = Field(min_items=1) - client_endpoint: Optional[constr(regex=r".+:\d+")] # noqa: F722 - client_persistent_keepalive: Optional[Literal["off"] | int] + server_allowed_ips: list[IPvAnyInterface] = Field(min_length=1) + server_endpoint: Optional[ + Annotated[str, StringConstraints(pattern=r".+:\d+")] + ] = None + server_persistent_keepalive: Optional[Literal["off"] | int] = None + client_allowed_ips: list[IPvAnyInterface] = Field(min_length=1) + client_endpoint: Optional[ + Annotated[str, StringConstraints(pattern=r".+:\d+")] + ] = None + client_persistent_keepalive: Optional[Literal["off"] | int] = None class WgWizardConfig(StrictModel): - name: constr(regex=r"[a-zA-Z0-9_=+.-]{1,15}") # noqa: F722 + name: Annotated[str, StringConstraints(pattern=r"[a-zA-Z0-9_=+.-]{1,15}")] listen_port: int - fw_mark: Optional[Literal["off"] | int] - addresses: list[IPvAnyInterface] = Field(min_items=1) + fw_mark: Optional[Literal["off"] | int] = None + addresses: list[IPvAnyInterface] = Field(min_length=1) # TODO: test DNS DHCP dns_addresses: list[IPvAnyAddress] = Field(default_factory=list) - mtu: Optional[int] - table: Optional[str] + mtu: Optional[int] = None + table: Optional[str] = None pre_up: list[str] = Field(default_factory=list) post_up: list[str] = Field(default_factory=list) pre_down: list[str] = Field(default_factory=list) post_down: list[str] = Field(default_factory=list) - default_endpoint: constr(regex=r".+:\d+") # noqa: F722 + default_endpoint: Annotated[str, StringConstraints(pattern=r".+:\d+")] peers: dict[ - constr(regex=r"[a-zA-Z0-9_=+.-]+"), WgWizardPeerConfig # noqa: F722 + Annotated[str, StringConstraints(pattern=r"[a-zA-Z0-9_=+.-]+")], + WgWizardPeerConfig, ] = Field(default_factory=dict) _yaml: dict = PrivateAttr(default=None) @@ -82,7 +89,7 @@ def dump(self, path: Path, overwrite=False): yaml = YAML() yaml.indent(mapping=2, sequence=4, offset=2) if self._yaml is None: - yaml.dump(json.loads(self.json(exclude_unset=True)), path) + yaml.dump(json.loads(self.model_dump_json(exclude_unset=True)), path) else: yaml.dump(self._yaml, path) @@ -104,13 +111,16 @@ def add_peer(self, name: str, peer_config: WgWizardPeerConfig): if self._yaml is not None: if "peers" not in self._yaml: self._yaml["peers"] = {} - self._yaml["peers"][name] = json.loads(peer_config.json(exclude_unset=True)) + self._yaml["peers"][name] = json.loads( + peer_config.model_dump_json(exclude_unset=True) + ) class WgWizardPeerSecret(StrictModel): private_key: SecretStr - public_key: constr(min_length=1) - preshared_key: Optional[SecretStr] + public_key: str = Field(min_length=1) + preshared_key: Optional[SecretStr] = None + issued_on: Optional[datetime.datetime] = None @classmethod def generate(cls) -> "WgWizardPeerSecret": @@ -120,6 +130,7 @@ def generate(cls) -> "WgWizardPeerSecret": private_key=private_key, public_key=public_key, preshared_key=preshared_key, + issued_on=datetime.datetime.now(datetime.timezone.utc), ) def check(self, name: str): @@ -131,30 +142,40 @@ def check(self, name: str): self.preshared_key.get_secret_value(), f"Peer {name} preshared_key" ) + @field_serializer("private_key", "preshared_key", when_used="json-unless-none") + def dump_secret(self, v): + return v.get_secret_value() + class WgWizardSecret(StrictModel): private_key: SecretStr - public_key: constr(min_length=1) + public_key: str = Field(min_length=1) + issued_on: Optional[datetime.datetime] = None peers: dict[str, WgWizardPeerSecret] = Field(default_factory=dict) @classmethod def generate(cls) -> "WgWizardSecret": private_key, public_key = gen_key_pair() - return cls(private_key=private_key, public_key=public_key) + return cls( + private_key=private_key, + public_key=public_key, + issued_on=datetime.datetime.now(datetime.timezone.utc), + ) def regenerate_server_secret(self): self.private_key, self.public_key = gen_key_pair() + self.issued_on = datetime.datetime.now(datetime.timezone.utc) @classmethod def from_file(cls, path: Path): check_file_mode(path) - return cls.parse_file(path) + return cls.model_validate_json(path.read_text()) def dump(self, path: Path, overwrite=False): path = path.resolve() logger.info("Writing secret to %s", path) ensure_file(path, mode=0o600, overwrite=overwrite) - path.write_text(self.json(indent=2)) + path.write_text(self.model_dump_json(indent=2)) def generate_peer_secret(self, name: str) -> WgWizardPeerSecret: peer_secret = WgWizardPeerSecret.generate() @@ -166,6 +187,10 @@ def check(self): for peer_name, peer_secret in self.peers.items(): peer_secret.check(peer_name) + @field_serializer("private_key", when_used="json") + def dump_secret(self, v): + return v.get_secret_value() + class WgWizard(StrictModel): config: WgWizardConfig diff --git a/src/wg_wizard/utils.py b/src/wg_wizard/utils.py index 78aefde..db52f0d 100644 --- a/src/wg_wizard/utils.py +++ b/src/wg_wizard/utils.py @@ -7,7 +7,7 @@ import stat import click -from pydantic import BaseModel, SecretStr, Extra +from pydantic import BaseModel, ConfigDict, SecretStr from .wg import pubkey @@ -17,19 +17,18 @@ def to_camel(string: str) -> str: class StrictModel(BaseModel): - class Config: - extra = Extra.forbid - validate_assignment = True - validate_all = True - json_encoders = { - SecretStr: lambda v: v.get_secret_value(), - } + model_config = ConfigDict( + extra="forbid", + validate_assignment=True, + validate_default=True, + ) class StrictCamelModel(StrictModel): - class Config: - alias_generator = to_camel - allow_population_by_field_name = True + model_config = ConfigDict( + alias_generator=to_camel, + populate_by_name=True, + ) def ensure_file(path: Path, mode: int, overwrite=False): @@ -55,7 +54,7 @@ def check_file_mode(path: Path): def format_ini_lines(obj: BaseModel, exclude=None): - for field_name, field_config in obj.__fields__.items(): + for field_name, field_config in obj.model_fields.items(): if exclude is not None and field_name in exclude: continue field_val = getattr(obj, field_name) diff --git a/src/wg_wizard/wg_quick.py b/src/wg_wizard/wg_quick.py index 7004dbf..b23735c 100644 --- a/src/wg_wizard/wg_quick.py +++ b/src/wg_wizard/wg_quick.py @@ -8,17 +8,17 @@ class WgQuickInterfaceConfig(StrictCamelModel): private_key: SecretStr - listen_port: Optional[int] - fw_mark: Optional[Literal["off"] | int] - address: list[IPvAnyInterface] = Field(min_items=1) + listen_port: Optional[int] = None + fw_mark: Optional[Literal["off"] | int] = None + address: list[IPvAnyInterface] = Field(min_length=1) dns: list[IPvAnyAddress] = Field(alias="DNS") - mtu: Optional[int] = Field(alias="MTU") - table: Optional[str] + mtu: Optional[int] = Field(None, alias="MTU") + table: Optional[str] = None pre_up: list[str] post_up: list[str] pre_down: list[str] post_down: list[str] - save_config: Optional[bool] + save_config: Optional[bool] = None def format_ini_lines(self) -> list[str]: yield "[Interface]" @@ -26,12 +26,12 @@ def format_ini_lines(self) -> list[str]: class WgQuickPeerConfig(StrictCamelModel): - comment: Optional[str] + comment: Optional[str] = None public_key: str - preshared_key: Optional[SecretStr] - allowed_ips: list[IPvAnyInterface] = Field(alias="AllowedIPs", min_items=1) - endpoint: Optional[str] - persistent_keepalive: Optional[Literal["off"] | int] + preshared_key: Optional[SecretStr] = None + allowed_ips: list[IPvAnyInterface] = Field(alias="AllowedIPs", min_length=1) + endpoint: Optional[str] = None + persistent_keepalive: Optional[Literal["off"] | int] = None def format_ini_lines(self) -> list[str]: yield "[Peer]" diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..1a201f7 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,15 @@ +import pytest + + +def pytest_addoption(parser): + parser.addoption( + "--update-snapshot", + action="store_true", + default=False, + help="Whether to update the test snapshot.", + ) + + +@pytest.fixture +def update_snapshot(request): + return request.config.getoption("--update-snapshot") diff --git a/tests/data/default_with_one_client/expected_wg_quick_config/wg0_None b/tests/data/default_with_one_client/expected_wg_quick_config/wg0_None new file mode 100644 index 0000000..fc2dfbf --- /dev/null +++ b/tests/data/default_with_one_client/expected_wg_quick_config/wg0_None @@ -0,0 +1,85 @@ +[Interface] +PrivateKey = uHcLp64yKEPEX9BVGtonUiZZRI03wK3pbwtCGuoIPEQ= +ListenPort = 51820 +Address = 192.168.10.1/24 +PostUp = iptables -A FORWARD -i %i -o eth0 -j ACCEPT +PostUp = iptables -A FORWARD -i eth0 -o %i -j ACCEPT +PostUp = iptables -t nat -A POSTROUTING -s 192.168.10.0/24 -o eth0 -j MASQUERADE +PostUp = iptables -A FORWARD -i %i -o %i -j ACCEPT +PostUp = iptables -A INPUT -d 192.168.10.1 -i %i -j ACCEPT +PostUp = iptables -A INPUT -i %i -j DROP +PreDown = iptables -D FORWARD -i %i -o eth0 -j ACCEPT +PreDown = iptables -D FORWARD -i eth0 -o %i -j ACCEPT +PreDown = iptables -t nat -D POSTROUTING -s 192.168.10.0/24 -o eth0 -j MASQUERADE +PreDown = iptables -D FORWARD -i %i -o %i -j ACCEPT +PreDown = iptables -D INPUT -d 192.168.10.1 -i %i -j ACCEPT +PreDown = iptables -D INPUT -i %i -j DROP + +[Peer] +# client_0 +PublicKey = SD6+qGbpgMapjVmg1FFmkDJEbHPgFfEz2cOcHWhYwEc= +PresharedKey = 7fjcVDKEf//f4K8dVaOJSPrRgxP9ga+4TXo5ooITiIE= +AllowedIPs = 192.168.10.2/32 +                                                                                                                              +                                                                                                                              +    █▀▀▀▀▀█ ▄▀▀ ▄▀  ▀▀ █▄▄▀▄▄    ▀▀ ▄▀▄▀▄▄▀▄█▄██     ▄▀▄▀▄▀ ██▀▄█ ▀▄█▄▀▄▀█▀ █▄   ▀▀█▄█▀▀ ▀▀▀▄▀▀█▀▄▀ ▄▀▀█  ▀██ ▀ ▄ █▀▀▀▀▀█     +    █ ███ █  █▀ ██▀▄▀█▀▀█▀▀▀▀   █▀▀█▀█▄▀▄█▀ █▀█ ▀ ███▄▀██▄  ▀█▀▀▀███▀ ▄▄▀█▀ ▀  █▀   ▀▄ ██ █▀▀▄ ▀█▄ ▀█▄▄█▀ ▄▄▀ ▀▀▀ █ ███ █     +    █ ▀▀▀ █ ▀▀  ▀▀▄█ ▀ ▄ ▀▀▀   ▀ ▀█▀▀▀██▄ ▀▄▄   █▀  ▀█▀█▀  ▄█▀▀▀█▄ ▀▀▀▀█▀▀ ███  ▀ ▀  ██▀▀▀█▄██▀▄█ ▀▀▀█▀ █▀▀ ▀ █▄  █ ▀▀▀ █     +    ▀▀▀▀▀▀▀ ▀ █▄▀▄█▄█▄█ ▀▄█ ▀ ▀ █ █ ▀ █ ▀ ▀▄▀ ▀▄▀▄█ ▀▄█ █▄█ █ ▀ █▄█ ▀▄█ ▀▄▀ ▀▄█ ▀▄█ ▀▄█ ▀ █▄▀▄█▄▀▄█ ▀ █ ▀▄█ ▀ █▄█ ▀▀▀▀▀▀▀     +    ▀ █▄▀▄▀ ▄▀▀▀█▀▄█▄▀ ▀▀▀▀  ▀▄ ▀ ▀█▀▀█ ▄▄█▀ ▀ ▀▄ ▀▄▄▄█ ▄▀▄▀▀█▀▀▀▀█▀▀▀ ▀▀▀▀█▄▀▀ ▀█▀▄▀██▀█▀█▄▀█▄▄▀▄▀▄▄▄▀█▀ ▀▄ ▀▄▀▀▄  █ ▄█▄     +    █▄▄█▀█▀▀█  ▀█▀▄▀ ▀██▄▄▄█ ▀▀▄▀▀█▄█▀█▄▄ ▄▀▀▄▀▄█ █▀ ███ ▀█▀▀█▀  ▄█  ██ ▀██▀ ▀█▀ ██▀ ▀▄█ ▄█▄ █ █ ███▀█▀▄ ▀▀▄ █▀▀█▄▀▄▀▀▀▀▀     +    █  █ █▀ ▄▀▄ ▀██▀█  ▄  ▀█▀▀▄ ██▄▀ █▀█ ▀▀▀▄▄██▀ ▀▄▀▀ ▄▀▀ ▀ ▄▀▄▄▀█▄▀▄▀ ▀▄▀▄ ▄▀██▄▀▀▄ ██▀▄█▄▀  ▄▀▀ █▀▄█▄▀  ▄▀ ▀▄▀▄ ▄█▄ ▄▀     +    ▄▄▄█▄▄▀█▀███ █ ▀ ███▀▄▄█  ▀  ██  ▀ ▀ ▀ ▀▄ ▀█▀ ▀  ▄█  ▄█▄▀ █  ██   █▄  █  ██▀ ▀▀ ▀ ▀  ▄█▄ ▀█▄ █▀█ █▀▄ █▀▄  █▄▀ ▀▀▀▀▀▀▀     +    ▀ █ ▄▀▀█▄ █▀▀ ▀█▀▀▀▄███▄▄▀▄ █▄ █▄▀█ ▀▄▀ ▄████▀▄ █▄▀▀▀▀▀▄ █ ▀█▄██▀ ▀██▄▀▀▀  ▄▀▀▀ ▀ ▀▀▀▄▀██▀███ █▄▀▄▀▄▀   ▀█▀▀▀▄▀▄▀███      +    ▄▀▄▄  ▀▄▀▀▄▀ ▀█▄█  █ ▀▄▀█  █   ▀▄▄ ▄ ▀▄█  ▀▄▀███ ▄█  █▀█ ██▀▀███ ██ ▀██▄ ▄█ █▀▀▄  ▄▀▀█▀▄ ▀█  ▀▀▀▀█▀█ ▀█  ██▀ █ ▀▀▀▀▀█     +    ▄██▀█▀▀ █ ▄█▄▀▄██    ▄▄█   ▀▄▄  ▄▀ ▀▀▄█▄▄ █  █▀  ▄▀▀█▀▀█ ▄▀▀▄▄▀ ▄█▄█  █▄▀█▀ ▄▀ █████   ▄▀▄▀▀█▀▀▄██  ▄▀▄▀▀  ▀█  █▄▄▀██     +    ▀▄ ▀▄ ▀ ██ ▀▀▄▄ ▄   █▀▄█ █    ▄▀█ ▀ █▀▀███▄████  █▀  ▀▀█▀██▄ ▄█▀▀█ ▀ █▀ ▀▀▀  ██ ▀▀▀▄ ▄█ ▀▄█▄ ██  ██▀  █▄  █▀▄▀ ▀▀ ▀██     +     ▀▀ ▄▀▀▀ █ █▀▄▀▀▄▀▀█▄▄███▀ ▀██▀▀▀▀█▀▀▀ █▀█▄ ▄▀▄▄  █▄▀ ▀█  █▄▄█▀▄▄██▄▀ ██ ▄▀ ▀█▄█ ▀▀▄▀▄▄▄▀▄  ▀ ▀▄ ▀▀█  █▄▀▀ ▄█ ▄ ▀█ ▄█     +    ▀▄▀██▀▀▄█ █▀██ ▄▀█▀███▀█▀ ▀ █ ▀█ ▄▄▀▄▄▀▄ ▄▄▀▀▀▀█ ▄█▀▀ █▄█▀█  ▀▀▄  █ ▀▄█▀▀▄█   █  █▀▄ ▀▀ ▀ █▀▀ █  ▀█  █▀▄ ▄█▄█ ▀█▀█ ▀▀     +    ▄██ ▀ ▀▄█▀▄ ▄▄▄█▀▄▀█▀▄▄█▄██    ▀▀▀█▀▄ ▄▄▄ ▀▀▀ █▄▀▀▀▀▀  █▀▄  ▀▄▄▄▀▀▄█▀▀ ▄▄▄▀▄ █▀▄▀▄▀███▀█▀▄ █▀▄▀ █▄▀█ ▄▀ ▀▀ █▀  ▄█▄ █▀     +    ██▄██▀▀▀██▀▄▀▀▄ ▀▄ ▄██▀███  ▀▀█▀▀▀██▄█▄▄ █▀██▄█  ▀█▄ ▀███▀▀▀█▀▀  ▀█▄ ▄█ ▀▄█▀ ▄█▄▀▄█▀▀▀█▀▀ █▄ ▀▀▄ ▄██ ▀█▀▀██▄█▀▀▀█ ▀▀▄     +    ██▀██ ▀ ██  ▄█ ▀█  ▀▄▀█▄▀ ▀▄  █ ▀ ██   █▀▄█▄ ▄▀█▀▄▀▀██▄▄█ ▀ █▀█ ▀  ▄▀█▀▄  ██▄█▀▀█▄█ ▀ ██ ▄▀▄▀▀ ▄▀▀▀█ ▄██▀▄█ █ ▀ █▀  █     +    ▀██▀██▀█▀ ▀▄  █▀▀▄   ▄▀▄ ▀▄▀  █▀█▀▀▄▄█▀▄ ▄▀██▀██ ▀█  ▄████▀▀███▄ ▀█▀ ▀▀▄ ▀▀   █▄ ▄███▀▀▄ █▀▄ ██▄ ▀▀  ▄█▄ ▀▀█▀███▀▀ ▄█     +    ▄███ ▄▀ █▄▀▄ ▀  ▄ ▀  ██  ▄ █▀▀█ ▀ ▄ ▄ ▄ ▀▀▄█ █▀▄▀▀█ ▀ █▄   ▄▀▀▄ ▀█▀██▄▄▀▄█▀▀█▄ ██▄▀ ██▀▄▀▀▀ ▀▄███ ▀▄ ██▄▀▄▀  ██ ▀▄ ▀▄     +     █▄ ▄ ▀ ▄▄ ███ ▄▀▄█ ▄▀   ▄▄▄▀▄▀▀ █  ▀█▀ ▀▀█▄▄▄█ ▀██▄ █▀██▀▀ █▀█ ▀▀▀█ ▄█▄ █▀▄ ███▀ ▀█▄█▀▄ ▀▀▄ ▀▀█ ██ ▀███ ▄█▄ ██  ▄▀ █     +    █▄▀▄  ▀▄▄█▄▀█▄▄ █ ▀▄ █▀▀ █▄█ ▄▀ █▄ ▄█▄  ▀▄▀▄▄▄█▀█▄▄▄ ▄▄ █▀ ▀▀ ▀██▄▀█▀▄▀▄▄ ▀▄▀▀▄█▀▀█▀▀▀▀▄▀▀ ▄█▄▀▄█▄▀█ ▀██▀▄ ▄▀██▄▀ ▄       +     ▀█▀█▄▀█▀█▀▀▀█▄▄▀█▄███ █▄▀  ▄ ▄ █ ▄  ▄▀ ██▄▀ ▀▀▀▀▀▀▄▀▀▀▄█ ▀█  ▀ █▀▀▀▀▄▀▀▀█▀ ▀█▀  ▄▄██ ▀▄ ██▄ ▄█▄ ▀█▀▀█▀▀  ██ ▄   ▀▀█▀     +     ▄ █▄▀▀▀ ██▄█▀▀▀▄▄██▀ ▀ ▀▀█▀█ ▀ ▄██▄ ▄    ▄ █ ▀▀▄█▄ ▀██▄ ▄▄▀▀ ▄ ▄  ▀▀▄▀▀▄█▄▄▀█▄▀▄▀  ▀▄▄█▀█▄▄▀▄▀█ ▄ ▄▄  █     ▄█ █ █▄▄     +    ▄ ▄▄▄█▀█ ▀ ▀ ▄███ ▄▀▄  ██▀█▄▀▄ ███▄██ ██▀   █▄██  █▀ █▀▄▀   ▀█▀   █▀ █▀   █ ▀█   ▄█▄▀▀▀ ▀ █ ▀▄█▀▀▀▀   █  ▄██▀   ▀ ▀ █     +     ▄  ▄▄▀▀█▄▀█▀▄ ██▀▄ █▄█▀███▀▀█ ▀  ██▀▀▀ ██ ▄█▀ ▄  ▀▀▄█▀ ▀▀███▄▀ █▄▀█ ▄▀▀█  █▀▄▀█   ▀█▀█▀▄▄▀▀▀▄▀▀▄▀█ ▀▀▀▄ ▄▀▄ ██▄▀  ▄▀     +    █▄ █ █▀▀██ ▄ ▄▀█▀  ▀▄▄ ▄███▀█ ▀▄▀██▀▄▀▀█  █▄█▄█▀ ██▀ █▀██▄ ▄▄ ██ ▀█  ▄█▀ ▄█▀▀ █ ▀▄▄▄▀█ ▀ ▄█▀▀▄█▄ ▀█▀▀███ ▄██▄▄▄ ▀ ▀▀▀     +    ▀▀▀█ ▄▀█▀ █▄█ █  █  ▀   ▀█ ▀█▄ ▀   █▀█▄▄▄ ▀▄▀▄███▄▀██▄▀▄ ▄ ▀█ ▀▄▀▄▀▄▀▀▄█  ▀▀▄▄▄█ ▄▀ ▀▀▄█▀▀▀▄▀▀ ▄▀▄█▄▀▄█ ▄▀▀  ▀▀▄ ▄ ██     +    ▀▀▀▄▀▀▀█▀▀▄▄▀█▀  ▄█▄▄█▄██  ▀██▄ ▄▀▀ █▀ ██▄▀█▀██▀ ██▀▀▀█ █ ▀█▀██   █  ▀▀█ █▀▄ █▀▀▀ ▀█▀▀▀ ███  ██▀▀▄▀▄ █▀▀▀▀██  █▀  ▀██     +    ▄█ ▄█▀▀▀█▄▀ ██ ▄▄▀█▀▄ █ █ ▄  ▀█▀▀▀█▀ █▄  █▄█▄▀ ▀▀▄▀ ▀█▄ █▀▀▀█▄▀▄▀ █▄▀▄▀▄▀▀▀▄▀▀▄▀▀ █▀▀▀█ ▄▄█ ▀▀▀ ▄▀▀ ▀▄▀█ ██ █▀▀▀█▄ ▄█     +    ▀ █ █ ▀ █▀▄ ▄▄▀█ ▀▀ ▄▀▄██▄ ▀ ██ ▀ █ ▄█▀▀▀▄▀▄▄▄█ ▀▀▀▀ █ ▀█ ▀ █ █ ▀█▀█ ▀█▀ ██▄ ▀█▄ ▄█ ▀ █▀▀█▀  ▀██ ▀▀  ██  █▀▄█ ▀ █ ▀▄▀     +    ▀ ▀▄▀█▀████▀▄▄ ▀▄▀▀██▀██ ▄▄█▀▄█▀▀█▀▀ ███ ▄▀ █▀▀  ▀▀▀▀  ▄█▀██▀▄▀▄▀▄█▄▀▀▀▀█  ▄▀ █▄██▀▀▀██ ▀▄▀ ▀█  ▄▄▀▄▀▀ ▄ ▀▀█▀█▀▀█▄▄ █     +     █▄ ▄▀▀ ▄█▀█ █▄ ▄▄█ ▄▀█▀▄▄█ ▀▄▀ ▄▀▄▄▄▄▀▀▄▀▄ ▄█▀  ██▄ █▀█▀ █ ▀██▄ ███▀▀▀ ▀█▀ ▀█▀▄ ▄ ▄ ▀ ▄▀███ ██▄ ██  ██▀▀▀██    ▀ ▀ ▀     +    ▄█▄███▀▄███▄ ▄▀▀▀▀ █ ▀▀ ▀ ▀▄ █▀█  ▀▀▀█▀▄▀▄█▄▀▄ █▀ ▄█▀▄  ██▀▀  ▀██ ██▀▀ █▀ ▀▄▀▄▀▄▀ ▀▄ ██▀█▄▄█▀  ▄▀ ▀▄    ▀  ▀▀▄▀██▄  █     +    ▀▄█ █▀▀▄█▀▄  ██▀█▄▄█ █  █▀▄▄  ▄  ▀██▄█▄█▄▄ ▀▀▄█  █▀█  █▄▀ █▄▀ █▀ █▀ ▀██▀▀ ▀  ▄█ ▀▄ ▀▄█▀▀ ▄█ ▀▀█▀▀ █▄ ▄█  ▀█▀▄  ▄ █▀▀█     +    ▀▀▀ ▄▄▀▄▀▀ █▀▀  ▄▀▀▀▄▀▀ ▀ ▀ ██▄█▀ █▀▄ ▄  ▄ ▀ ▀▀ ▀██ ▄▄▀▄▀▄█  ▄█▄▀▄▀▄▄  ▄▄▀▀▀▀  ▀▀ ▀▄ ▀▀▀▀▄▀█   █▀▀  ▀▄▀▄▀█▀▄   ▀██ ▀▄     +     ▀▀▀█▄▀▄█▀█▄▀██▀▀  ▀▄▄▄▀▀▀▀█ ▄▀▀ ▄▀▀ ▀ ▄▀▀▀██▀█ █▄██ ▄█▀█▀  ███▀ ▄█▄ ▄█▄ █▀▀▀█▀▄  ▄▄▄█▀▄ ▄█  ██▄ ██▀▀ █ ▀▄█▄▀ ▀ ▄▀▀▀▀     +    █ ▀▄▄█▀▀▀▄ ▄███   ▀ █▀▀▄█▄█    █▀▄ ██ ▀▄ ▀▄▀▀█▀ ▄▀ ▄▀█▀▄█▄██   ▀▄  ██▄▀▄▀ █▄▄ █ ▀▀▀█ █▀ ▀ ▀▄ █▄▄▀▀ █▀▀ ▄▀▄██ ▀▀▄███ ▄     +    █ ▄  ▄▀█▄ █▀▄▀▀██▄█▄  ▀▄ ██ ▀ ▀▀▀██ ▄▄█ █ ▀▄▀███ ▄█  ████▀▄  ▀█ ▀█▀ ▀██  ▀█▀▀▀█▀ ▄▀▄  ▀█  ██▀█ ▄ ██▄ █▀ ▀▀▀▄▀▀ ▀▀▀▀▀▀     +    ▀███▄▄▀█▄▀█▀█▀▄▄▄▀███ ▄ ▄▄▀███▄██▄▄█ ███  ▀ █▄▀▄▀ ▀█▀▄▀ █▀█▀ ▄▀ ▄█▀▀ ▀▀ ▀▀▀ ▀█▀▀▀▀▀ ▀█▀██▀ █▀▄▀███▀█▀▀█▀ █▀ ▀▀▀█▀▀▀▀█     +      ▀▀▄▀▀▄▄▀██ ▀ █▀ ▄██ ▄ ██   ██▀█▄█▀▀▄  ▄▄▄██▀█▄  ▀ ▀▄█▄▀▄▀▀▄▀▀  ██▄ ▀█  ▀█ ▀▄▀▀ ██▄▀█▄  █▀  ▀█▄ ▄██ █▀▄ ▄█▄ █ █▀▀▀▀▀     +     ██▀▄ ▀▀▀█ ▀█▀██▀▄▄▄ ▀ ▀▀ ▄▄▄▄██▄ ▀▄█▀▀▄▀█ ▄ ▀ ▀▄▀█▀█▄▀▄██▀▄ ▀▄▀█▄▄▄▀▀ ▄██▀ ▄▄▀▀▀█▀ ▀ █▀█ ▄▀ █▀▀▄▀ █▀▀ ▄▀▀ ▀ ▄▀▀██ ▄      +    ▀  ██▀▀▀█▄▄█▄ ▀ █ ▀▀▀██   █ ▄▄█▀▀▀█ █▀▄█▄█▀█▀▄▀ ▀▀██ ▄███▀▀▀█▀█▀▀▀▀▄ ▄▀ █▄▀  ▄█▄ ██▀▀▀█ ▀██ ▀█▀█ █▀▄ █▀▀ ▄█ █▀▀▀█▀▀█▀     +    █ ▄██ ▀ █▄▀▄▀▀▄ █ ▀▄▄▄▀███▄█ ██ ▀ ██▄▄█ █▄▀█▀▀▀ ▀▄▄▄ ▀ ▄█ ▀ ██▀▀▀▀▀███▄ ▄▄▀▀█▄▄▄▀ █ ▀ █▄▀ █▀ █▄  ▀▄▄▀ ▀▄▀█▄▀█ ▀ ██▀▄▀     +      █ ▀▀▀█▀██ ▀▀▀██▀▀▄ █   ██▄█ ▀▀▀██ ▄▀▄ █▀▄▄ ██▀ █▀▀▀█▀▄▀█▀▀▀▄▀ ▀██▀▀█  ▀█▀▀▀▄█  █▀▀▀█▀   █   █▀ ▄█▄ ██▄ ▀█▀▀██▀▀█▀▀█     +    ▄▄▄▄▄▄▀▀ ██▀█   ▀█  ▄▀▀ █▀█ ▀▀▀█▄▄█▄▀▄▀▀█ █▄ ██▀▀▄▀▄ █ █▄▄▀█▄▄▀▀▀▄▄▄▀█ ██▄▀▀▀▄ ▀████▀▄▀ ▄ ▄██▀▀▄ ▄█▄▄▀▄█ ▄▄ █▀▀  ▄ ██     +    ▄█▄▀ █▀▄█ ▄█▀█▀█▀ █▀▄▄▄▄  █▀▄▀█▀█▄█▄▄  ▄█▄  ▀ █▄▀█▀█▀██▄▀ ▀███▀ ▀▄█  ▀█ ▀▄█▀  █▀▀▄▀█▄ ▄▄  █▄ ▀█▄▀▄█  ▄█▀▀ ███▀▀█   ▄▀     +     ▄█▄ █▀█▀ ▄█▀▄▄▀██▀▄█▀▀█▄▀  ██  ▀█▀▀▀▄▀█  ▄ ▀   ▀█ █▀ ████ ▄█▄▀█  ▀▄ █▄ ▀▄▀█ ▄ ▀▀▄▄█▄▀▀ ▀ ▀█ ▀▀▀█   ▄▄█▀▄▄▄▄ ▄█▀  ▄▄█     +      ██ ▀▀   █▀█▄▄ ▄ ▀ ▄▄▀▄  ▀█▄ ▀  ▄▀ █▀ ▀█▄  ▀ █▀ ██▄ ▀████  ▀▄█▄ ▀█▀▀▀▀  ▄█   █  ▄▀█▀ ▄▄  ▀▄ ▀█ ██▀▄ █▀▄ ▀▀▄███▀▄█ █▀     +    ▀█▄▄█▄▀██▀▄▄█▀▄  █  ▀▄ ██▄▄  ▀▄▀▄█▀▀ █ ▀▀▄ ▄ █▄██▄▀█ ▄▀█▀▀ ▀ █▄▀█▀ ▀▀▀ ▀ ▀▄ █▄▀▄▀▄▄ ▄▀▀████ ▀ ▀ ▄█▀ ▀█▄█ ▄▀ ██▀▀ ▄ ██     +     ▄  ▄ ▀  ▀ █▄▄█▀ ▄▀▄▀▄ ▄▀█  █▀  ▄█▄▄▄▀▀ ▀▀▄▄ █   ██ ▀██▀▄▀▀▀▀▄█  ▄█  ▄█▄ ▀█▄ █▀▀▀▄▄█▀    ██  ▄█▀▀▄█▄ ▀▀  ▄█ █▄█▀▀  ▄▀     +     ▀▀   ▀▀▄ █ █ ▀▀ ▀▄▄▀ ██▄▀█▀▀ ▀ █▄  ▀ ▀ ▀██▄▄▄▀▄ ▀▄█▄█▀▄  ▀█▀▀▀ ▀█ ▀▀▀▄▄▀▄▀▀█▄█▀▀█▄ █▄▀▀█▀▀▀▀ ▀▄█████▄▀▀█▀▀▄ ▄█▄  █ ▀     +    ▄█▀█▄ ▀▄▄▀ ▄█▄▀▀▀▄█▄█▄█  █▀█▀█▀▄▄▀▀▄█▄ ██ ▀  ███  █  ██▄▄ ██▄█▀▄ ██ ▀▀█▄ ▄██▀█▀  ▄▄▄▀▄ █ ██▄ ▀▀  █▀▄ ▀█▄ ▀█▀▀██ ▀  ██     +    ▀▄██▀█▀ ▄█ ▄█▀▀▄ ▄▀ ██▀▀ █ █▀▀ █▄█▀▀  ▀▀  █▄ █ █▀██  ▄▀█▄ ▄█▄▀ ▄  ▀█▀ ██▀▄██▀▄▄▀▀▀ ▄▀▀▀█▀█▄▄▀  ▀ ▀▀▄ ▄▀▄▀▄▀ █▀ █ ▀▀ █     +    ▀ █ ▀█▀▀ █ ▀▄ ▀▀▄ ▄██▄▀▀█▀▄██▄▀▄  ▀▄█▄███▀   ██▀ █▀▀▀▀▀ █ ▀▀███▄▀ ▀▀▀█▀ ▀█▀▀▀▄█ ▀▀ ▀▀█▀▄  █▀ ▄█  ▀██ ▄▀▄  █▀▀▄█ ▄ ▀█▀     +     ▀▀   ▀ ▄▄▀█▄█▄█▄█▀█▀█ ▀▄▄ █  █▀▀▀█ ▄▄▄██ ██▀▄▀▄▀▄▀█▄  ▀█▀▀▀█▄█ ▀█▀▄▄▄▀█ ▀ ██ ▀█▀██▀▀▀█▄▄▄▀▀███▀▀█▀█▄▀▄▄▀▄▀▄█▀▀▀█▄ ▀▀     +    █▀▀▀▀▀█  ▄▄▀▀  ▄█▄▀ ▄  ▄▄▄▄▀▀██ ▀ ██ █▄▀▀▀ ▄ ██▄ ▄█ ▀ █ █ ▀ ██▀▀ ▀█ ▀ █▄▀██▀  █▀▀▄█ ▀ █ ▀▄█ ▀ █  ██  ██▀  █▄█ ▀ █▄▀██     +    █ ███ █ ▀█▀██ ▄▄██▄ ▀ ▀█▀▀▄▀█▄███▀▀ ▄▀▄█ ▄ █ █▀ ▄▄▀█ ▄▀ ▀▀▀▀▀██▀▀▄█▄▀▄▀▀▀▀ █▀▄▀▄▄▀▀███▀▄ ▄▀▀ ▀▀▄ ▀ █▀▄█▀█  ▄▀▀███  █      +    █ ▀▀▀ █ ▀█▄▄█▀▀▀▄ ▄▄▄ ██▀█   ▀▀▄  ▀█▀▄  ▀ ▀█ ██  ▄██ ▀██ ▀▀  ██▀ ▀█▀ ██▀▀██▄ ▄██ ▀██ ▄█▀▀▄█▄ ▀▀▄ ███ ▀▀ ▀▄████ ▄█ ▀▄▀     +    ▀▀▀▀▀▀▀ ▀▀▀ ▀ ▀▀▀     ▀▀ ▀ ▀▀    ▀ ▀▀▀       ▀  ▀▀▀ ▀ ▀▀▀▀▀  ▀▀ ▀ ▀▀▀▀▀ ▀▀▀  ▀▀▀▀ ▀  ▀ ▀ ▀ ▀▀   ▀▀▀▀ ▀ ▀ ▀▀▀▀▀ ▀   ▀▀     +                                                                                                                              +                                                                                                                              diff --git a/tests/data/default_with_one_client/expected_wg_quick_config/wg0_client_0 b/tests/data/default_with_one_client/expected_wg_quick_config/wg0_client_0 new file mode 100644 index 0000000..136f571 --- /dev/null +++ b/tests/data/default_with_one_client/expected_wg_quick_config/wg0_client_0 @@ -0,0 +1,50 @@ +[Interface] +PrivateKey = aOIX/aK1w2Ig2s8Vvz7tU7CJ+22iT8Fsd/z3mbdhGn8= +Address = 192.168.10.2/32 + +[Peer] +PublicKey = j4qJbzJL7/FLPb6Sr5ZZ6LjKgvJTZ2kW+c744hELoWg= +PresharedKey = 7fjcVDKEf//f4K8dVaOJSPrRgxP9ga+4TXo5ooITiIE= +AllowedIPs = 0.0.0.0/0 +AllowedIPs = ::/0 +Endpoint = example.com:51820 +PersistentKeepalive = 25 +                                                                              +                                                                              +    █▀▀▀▀▀█ ██▄▄█▄█▄ █   ▄ ▄▀█▀▄ ▄██▄█ █ █ ▄  ██▀▀▄▀█▄  ███ ▀█▀▀▀ █▀▀▀▀▀█     +    █ ███ █ ▄▀▄██▀▀▀▄▀▄▄▀▀ ▀ ████ ▄▀  ▀█▄  ▀▀▀██▀ ▀▄█▀▀▀ █▀▀▀ ▀ ▄ █ ███ █     +    █ ▀▀▀ █  ▀██▀▄██ ▀▀▀▄▀▄▄▀▄▀▄▄ ▀▀█▀▀▀█▀▀ ▀ ▄▀ █ ▀▄▄█ ▄▄ ▄ ▀█ ▀ █ ▀▀▀ █     +    ▀▀▀▀▀▀▀ █▄█▄▀▄█ █▄▀ ▀▄▀ ▀▄█▄█▄▀ █ ▀ █▄▀▄▀ █ ▀▄▀ █▄▀▄█▄▀▄▀▄█ ▀ ▀▀▀▀▀▀▀     +    ▀▄██ █▀█  ██▀ ▀▄██▀▀██▄  █ █ █ ▄███▀▀█ ▀█▄▀ ▄▄▀  ▀ ▀▀█▄█   ▀█▄▀▄ ▀ ▀█     +    █▄▀▄▀▀▀█  █▀▀▄█▄██▀▀█ ▄ ▄▄ █▄ ▄█ █▄▄▄ ▄ ▀█  ▀█▀▄██▄▄▀▀ ██▄█ █▄ ▀▀█▀▀▀     +    ██▄▀█▀▀▄ ▀▀▄▀▀  ▄▀▄   ▀ ▀ ▀█ █▀ █ ▄████▄▄▀▀▀ ▀▀▀█▄█▀ █ █ █    ▄▄▄▄██▄     +     █ ▄▀█▀▄█▀█ ▀▀ ▀▀█▀▀██▄ ▄▄▀ ▀ ▀▄  ▀█▄██▄███▄▄▀▄█    █ ▀█▄▄▀▄▄█ ▀▄ █▄▄     +    ▀ ▄▄▀▄▀▄ ▄▀▀█▀▀▄██▄▄ ▄█ █▄▄▀█ ▄██ ▄ ▄ ▄▄▄▀  █▄▄▄  ▀ ▄▄ ▀▀▄██▀ ▀▄  ▀▄      +    █▀▀███▀▄▄ ▄█▄▄▀▄ █  █▄█▄ ▀▄▀██▀█▄█▀ ▀ ▄▄▀▄     █▀▀██ ▄ ▀ ▀█▄▀▄▀▀▄▀ █      +    ▀▀ ▀▀▄▀██▄ ▄▄▀▀█ █▀▄▀▀ █▀▀   ▀  ▄██▀▀█  ▀ █▄▄▀ ▀ ▀ ▀█▄▄▄▄▄  ██▀ ▀ ▀█▄     +    ▄▄▀█▄▄▀█▀ ▄ ▀█ █▀▀▀▀▀▀▀███ ▄ ▀   ▄█   ▄  ▀ ▄█ ▀ ▄ ▄ ▄█▀▀▄▀█▄▄█▄▄▀▄▀█▀     +    ▄█▀ ▀ ▀ ███ █▄ ▄▄▄▄  ▄█▄▄███▀▀█▄█▀ ▀▄█▄▄▄▀ █ █ ▄▀▀▄█ ▀▀▀▄▀ ▀ ▄▄▄▄▀▀▀      +    ▀ ▄█▀▀▀▄▀▄▀▄█▄█ ▀▀▀ █▀▄██ ▄█▀ ▄▄▀▄▀█▄▀▀▄███▀▀█▀▄▄█▀█ █▄▀▄█▄▄█   █▀█▄      +    ▄█ ▀█▄▀▄▀ █▄ ▀ ▄██ ▀  ██▀ █▀█▀ ▀ █▀ ▄ ▀█▄▄  ▀ ▄▄   ▀ ▄▀██ █▄▀█ ▄  ▀ ▄     +    ▄▀▀▄ ▀▀█▄ ▀▄▄█ ▄▀█▄▄█ ██▄▄ ▄▀ ▀█▄▄▀█▀ ▀█ ▄ ▀ ▀▀▄▄ ███ █▀  █▀▀ █▀▄  ▄▄     +    ▀████▀▀▀█▀██▄█▄ ▀▀▄█▄▄ ▀▀ ▄█▀▄▄██▀▀▀█▀▀█▀▀▄  ▀▀▀ █▀▄█ █   ▀██▀▀▀█ ▀█▄     +       ▀█ ▀ ████ ▄▄▀▀█   ▀▀▄▄██▀▄██ █ ▀ ██▄▀ ▀▀▄█ █▄▄▄ ▀  ▀█    █ ▀ █▄▀██     +    ▀ █▀█▀▀█▀ ▄█▀▀█▄▀▄ ███▄█ ▄▄█▀ ███▀█▀▀▀▄▄▄▄▀ ▄▀ ▄▀ █▀▄  █▄█  █▀██▀  ▄      +      ▀▀ █▀▀██ ▄▄▀▀▄▄  █▄ ▀█▄▄█▄▀███▄▀▀▄▄▀█  ▄▄▀▄▀ ▄ ▄█  ███▄  █ █▄██▀█▀      +    ██ ▄ ▀▀▄▀█  ▄█ ▄ ▀▄ ███▀▄██▀█▀ ▀█▀ ▄█ ▀█▄  ▀▀▄▄▄ ▄ ▀ ▄▀ ▀▄▄▀█▀████▀▄▀     +      ▀▄ ▄▀██▀ ▄▄█▄▄▀▀▄██ ▀  █ ▀ ▀▀▄▀█  █▄▀▄ ▄ ▄▀▀█████▀█ ▄▄██  █▄  ▀▄ ▄▄     +    ▄▄ █▄ ▀▄ █ ▄▄▄▀█ █▀▀▄▀█▀▄█▀ ▀▀  ▀ █▄▀█ ██▀▄▄  ▀ ▄ ▀█▀██   ▀▄▀ ▄█  █ ▀     +    ▀██▄█ ▀ ▀▄▀   ▀▄▄█▄██▀▄▄▀▄▀▀ ▀█▄ ▀▀ ▀ ▄▄▀ ▄ █ ▄▀▄▄ ▀▀▀ ██▀▀▀▄ ██▀▄ ▀█     +    ▄▄▄▀█ ▀▄▄█▀██▄ ▄▀▄ ▀▄▄██▄▀▄█ ▀▀▄█ ▀▄▄▀▄▀▄█▀  ▀▀██▄▄▀ ▄▀█▄▄▀▄██▀█▀▄▄ ▀     +     ▀▄█▀ ▀█▀▀ ▀▄████ ▀▀▄ ▄▀▀█▄  ▄ ▀ ▄ ██ ▀ ▄▄▀█▄▄    ▀███▀▀▄  ▄█▄▄ █ █ ▄     +    ███▄▀█▀ ▄ ▄▄ ▄▄█▄▀▀ ▄▄▄▄ ▀██▄▄ ██  ▄██▀ ▄▄▀ █▄▄ ▄  ▄▄█▀▀▀▄█▀▄▄▄ █▀█▄█     +    ▄ ▄▀▀▀▀█ ▀▄▀▄ ██ ▄▀▄▀▀▀▄▄███     ▄▄█ ▀▄▀ █▄█▀▀█▄▀█ ▄▀█ ▀ █▀ ▀▀▄▄█▀▀█▄     +     ▀ █ ▄▀▀█▄ ▄ ▄ █▄▀▀▀▀ ▄ ▀▄▄  ▀▄▀▄███▀▄ █▄ █ ▄ ▀█ ▀▀███▄  ▀  ▀▄   ▀▀▀█     +    █ ▀ ▀▀▀█▀▄▀█▄▀█▄▄ ▄█▄██▄▄ █ ██▄ ▄██ ▀▄▀▀▀▀ █▀ █▄██ ▄▀██ ▀▀█▄▀██▀▀▄▀█▀     +    ▀  ▀▀ ▀ ▄█ ██▄▄ ▄ ▀▄▄▄ ▄ ▄▀█ ▄█▀█▀▀▀█▄█ ▄▄ █▄▀  ▀▄▄█▄█▀█▄  ▄█▀▀▀█▄▀▀▄     +    █▀▀▀▀▀█ █  ▀▀▀▀█▄▄▀ ▀ █ ▄▀ ▄▄ ▀▄█ ▀ ██▀█ ██▄▄▀▄  █▀█▀ ▄█▀▀  █ ▀ █▄█ ▄     +    █ ███ █ ▄█▄▀ █ ▄ ▀▄█▄▄ ▀▀▄▄██▄  █▀█▀▀▀▀▀ █ ▄█ █ ▄█▀▀ ▄▀█▀▄▄██▀▀█▀▄▀▄▀     +    █ ▀▀▀ █ ▀ ▄ ██▀▀▀▄▄▄▄▄▀█▄ ▄  █▄▀ ▀▄▄▀▄███▄█▄ ▄█ █ ▀██▄▀▀▄▄▀██▄▄▄ ▀▀ ▄     +    ▀▀▀▀▀▀▀ ▀  ▀▀▀ ▀▀ ▀▀   ▀▀▀▀ ▀▀▀  ▀ ▀ ▀▀ ▀▀▀  ▀▀▀    ▀▀   ▀▀▀ ▀▀▀▀▀▀       +                                                                              +                                                                              diff --git a/tests/data/default_with_one_client/wg0_secret.json b/tests/data/default_with_one_client/wg0_secret.json index e70df27..1ef1996 100644 --- a/tests/data/default_with_one_client/wg0_secret.json +++ b/tests/data/default_with_one_client/wg0_secret.json @@ -1,11 +1,13 @@ { - "private_key": "OGQSYTn0tCmAkx7Qkjad1u9X9dm3eS+uuVpSCvtcU3E=", - "public_key": "1ZtBZhxSURBrXG5eQgXnuU9KzBbTzsung0n0knUAIiw=", + "private_key": "uHcLp64yKEPEX9BVGtonUiZZRI03wK3pbwtCGuoIPEQ=", + "public_key": "j4qJbzJL7/FLPb6Sr5ZZ6LjKgvJTZ2kW+c744hELoWg=", + "issued_on": "2023-12-03T07:29:51.510215Z", "peers": { "client_0": { - "private_key": "YGg93ImbiR/siYoyhy7t+3MiCh2YJmCTofJuZtf/D24=", - "public_key": "8uiZIsUW9igOYVyK7gsFMp+ymOMwi4lBrN8dFZv7SGY=", - "preshared_key": "JYm7r7GFmeDcwDila+j8TINMKFDyD/QCsYwk4t7tZJQ=" + "private_key": "aOIX/aK1w2Ig2s8Vvz7tU7CJ+22iT8Fsd/z3mbdhGn8=", + "public_key": "SD6+qGbpgMapjVmg1FFmkDJEbHPgFfEz2cOcHWhYwEc=", + "preshared_key": "7fjcVDKEf//f4K8dVaOJSPrRgxP9ga+4TXo5ooITiIE=", + "issued_on": "2023-12-03T07:29:51.516539Z" } } } \ No newline at end of file diff --git a/tests/test_cli.py b/tests/test_cli.py new file mode 100644 index 0000000..1d4909b --- /dev/null +++ b/tests/test_cli.py @@ -0,0 +1,38 @@ +from pathlib import Path + +import pytest +from click.testing import CliRunner + +from wg_wizard.cli import add_peer, init +from wg_wizard.core import WgWizard + +data_dir = Path(__file__).parent / "data" + + +@pytest.mark.parametrize( + "expected_config_dir, interface", [(data_dir / "default_with_one_client", "wg0")] +) +def test_init_default_with_one_client(expected_config_dir, interface): + runner = CliRunner() + with runner.isolated_filesystem(): + result = runner.invoke( + init, + [ + "--interface", + interface, + "--default-endpoint", + "example.com:51820", + "--internet-interface-name", + "eth0", + ], + ) + assert result.exit_code == 0 + result = runner.invoke( + add_peer, ["--interface", interface, "--name", "client_0"] + ) + assert result.exit_code == 0 + assert ( + Path(f"{interface}.yml").read_text() + == Path(expected_config_dir, f"{interface}.yml").read_text() + ) + WgWizard.from_dir("./", interface).check_secret() diff --git a/tests/test_core.py b/tests/test_core.py index 4bf46ee..ffaf47d 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -2,16 +2,49 @@ import pytest -from wg_wizard.core import WgWizard +from wg_wizard.core import WgWizard, export_wg_quick_config_from_files from wg_wizard.paths import get_secret_path -parent_dir = Path(__file__).parent +data_dir = Path(__file__).parent / "data" @pytest.mark.parametrize( - "config_dir, interface", [(parent_dir / "data" / "default_with_one_client", "wg0")] + "config_dir, interface", [(data_dir / "default_with_one_client", "wg0")] ) def test_wg_wizard_from_dir(config_dir, interface): get_secret_path(config_dir, interface).chmod(mode=0o600) wg_wizard = WgWizard.from_dir(config_dir, interface) wg_wizard.check_secret() + + +@pytest.mark.parametrize( + "config_dir, interface, peer_name", + [ + (data_dir / "default_with_one_client", "wg0", None), + (data_dir / "default_with_one_client", "wg0", "client_0"), + ], +) +def test_export_wg_quick_config_from_files( + config_dir, interface, peer_name, request, capsys, update_snapshot +): + get_secret_path(config_dir, interface).chmod(mode=0o600) + export_wg_quick_config_from_files( + config_dir, + interface, + text=True, + qrcode=True, + invert_qrcode=False, + peer_name=peer_name, + ) + captured = capsys.readouterr() + assert not captured.err + + expected_output_path = ( + config_dir / "expected_wg_quick_config" / f"{interface}_{peer_name}" + ) + if update_snapshot: + expected_output_path.parent.mkdir(parents=True, exist_ok=True) + expected_output_path.write_text(captured.out) + assert expected_output_path.read_text() == captured.out + if update_snapshot: + pytest.skip("Snapshot updated.")