Compare commits

...

28 Commits

Author SHA1 Message Date
7b9d1a1159 new release: 0.8.14-beta 2020-04-10 21:23:55 +02:00
cdbe1f6161 bump dependencies 2020-04-10 21:17:31 +02:00
e43db2e065 new release: 0.8.13-beta 2020-04-10 21:11:24 +02:00
d1c74d2160 lib: fix imports being changed every time 2020-03-05 17:28:03 +01:00
f2119ce567 providers/saml: fix signing_kp typo 2020-03-05 17:09:08 +01:00
2c4dcb9cf0 actions: remove cache 2020-03-04 21:15:44 +01:00
93b8266821 actions: install pipenv as root 2020-03-04 21:13:40 +01:00
443797d9b0 actions: install wheel package 2020-03-04 21:11:26 +01:00
a4365ca02c actions: don't update system pip 2020-03-04 21:09:46 +01:00
3750083667 actions: don't setup custom python, use system pip 2020-03-04 21:08:24 +01:00
66ef067ecf actions: don't update pip to fix CI 2020-03-04 20:10:46 +01:00
b489b0e691 Merge pull request #7 from BeryJu/crypto
generic cert management
2020-03-04 19:43:52 +01:00
f2154d9875 crypto: add property for private_key 2020-03-04 19:43:18 +01:00
80a50f9bdb providers/saml: switch to new crypto 2020-03-03 23:35:50 +01:00
dc8b89a6b9 sources/saml: switch to new crypto 2020-03-03 23:35:38 +01:00
8df55f22aa crypto: implement simple certificate-key pair for easier management 2020-03-03 23:35:25 +01:00
f6c322be27 providers/oidc: fix skip_authorization not being synced to oidc_client 2020-03-02 17:40:38 +01:00
a144552059 providers/oidc: fill claims with userinfo 2020-03-01 22:55:56 +01:00
535d529193 ui: fix title, fix navigation on user settings 2020-02-29 14:46:58 +01:00
6ed2e137a2 new release: 0.8.12-beta 2020-02-28 11:54:03 +01:00
45bd63c720 api: update old field names 2020-02-28 11:48:55 +01:00
736e13fc35 ui: add template for csrf errors 2020-02-28 11:41:28 +01:00
966fff008c ui: re-enable branding on navbar 2020-02-28 11:37:07 +01:00
64f15eadbd providers/saml: fix CSRF errors with POST binding 2020-02-28 10:50:16 +01:00
81b66ecdcd core: remove some more dead code, add more help texts for factors 2020-02-27 16:39:30 +01:00
53e5cf7826 admin: fix some models not being paginated 2020-02-27 15:30:28 +01:00
82654b3fd9 ui: re-organize some of the navigation to make it cleaner for end-users 2020-02-27 14:59:34 +01:00
9b72c604dd docs: fix some typos 2020-02-27 13:00:55 +01:00
68 changed files with 1260 additions and 711 deletions

View File

@ -1,5 +1,5 @@
[bumpversion] [bumpversion]
current_version = 0.8.11-beta current_version = 0.8.14-beta
tag = True tag = True
commit = True commit = True
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)\-(?P<release>.*) parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)\-(?P<release>.*)

View File

@ -15,14 +15,8 @@ jobs:
- uses: actions/setup-python@v1 - uses: actions/setup-python@v1
with: with:
python-version: '3.8' python-version: '3.8'
- uses: actions/cache@v1
with:
path: ~/.local/share/virtualenvs/
key: ${{ runner.os }}-pipenv-${{ hashFiles('Pipfile.lock') }}
restore-keys: |
${{ runner.os }}-pipenv-
- name: Install dependencies - name: Install dependencies
run: pip install -U pip pipenv && pipenv install --dev run: sudo pip install -U wheel pipenv && pipenv install --dev
- name: Lint with pylint - name: Lint with pylint
run: pipenv run pylint passbook run: pipenv run pylint passbook
black: black:
@ -32,14 +26,8 @@ jobs:
- uses: actions/setup-python@v1 - uses: actions/setup-python@v1
with: with:
python-version: '3.8' python-version: '3.8'
- uses: actions/cache@v1
with:
path: ~/.local/share/virtualenvs/
key: ${{ runner.os }}-pipenv-${{ hashFiles('Pipfile.lock') }}
restore-keys: |
${{ runner.os }}-pipenv-
- name: Install dependencies - name: Install dependencies
run: pip install -U pip pipenv && pipenv install --dev run: sudo pip install -U wheel pipenv && pipenv install --dev
- name: Lint with black - name: Lint with black
run: pipenv run black --check passbook run: pipenv run black --check passbook
prospector: prospector:
@ -49,14 +37,8 @@ jobs:
- uses: actions/setup-python@v1 - uses: actions/setup-python@v1
with: with:
python-version: '3.8' python-version: '3.8'
- uses: actions/cache@v1
with:
path: ~/.local/share/virtualenvs/
key: ${{ runner.os }}-pipenv-${{ hashFiles('Pipfile.lock') }}
restore-keys: |
${{ runner.os }}-pipenv-
- name: Install dependencies - name: Install dependencies
run: pip install -U pip pipenv && pipenv install --dev && pipenv install --dev prospector --skip-lock run: sudo pip install -U wheel pipenv && pipenv install --dev && pipenv install --dev prospector --skip-lock
- name: Lint with prospector - name: Lint with prospector
run: pipenv run prospector run: pipenv run prospector
bandit: bandit:
@ -66,14 +48,8 @@ jobs:
- uses: actions/setup-python@v1 - uses: actions/setup-python@v1
with: with:
python-version: '3.8' python-version: '3.8'
- uses: actions/cache@v1
with:
path: ~/.local/share/virtualenvs/
key: ${{ runner.os }}-pipenv-${{ hashFiles('Pipfile.lock') }}
restore-keys: |
${{ runner.os }}-pipenv-
- name: Install dependencies - name: Install dependencies
run: pip install -U pip pipenv && pipenv install --dev run: sudo pip install -U wheel pipenv && pipenv install --dev
- name: Lint with bandit - name: Lint with bandit
run: pipenv run bandit -r passbook run: pipenv run bandit -r passbook
# Actual CI tests # Actual CI tests
@ -101,14 +77,8 @@ jobs:
- uses: actions/setup-python@v1 - uses: actions/setup-python@v1
with: with:
python-version: '3.8' python-version: '3.8'
- uses: actions/cache@v1
with:
path: ~/.local/share/virtualenvs/
key: ${{ runner.os }}-pipenv-${{ hashFiles('Pipfile.lock') }}
restore-keys: |
${{ runner.os }}-pipenv-
- name: Install dependencies - name: Install dependencies
run: pip install -U pip pipenv && pipenv install --dev run: sudo pip install -U wheel pipenv && pipenv install --dev
- name: Run migrations - name: Run migrations
run: pipenv run ./manage.py migrate run: pipenv run ./manage.py migrate
coverage: coverage:
@ -135,14 +105,8 @@ jobs:
- uses: actions/setup-python@v1 - uses: actions/setup-python@v1
with: with:
python-version: '3.8' python-version: '3.8'
- uses: actions/cache@v1
with:
path: ~/.local/share/virtualenvs/
key: ${{ runner.os }}-pipenv-${{ hashFiles('Pipfile.lock') }}
restore-keys: |
${{ runner.os }}-pipenv-
- name: Install dependencies - name: Install dependencies
run: pip install -U pip pipenv && pipenv install --dev run: sudo pip install -U wheel pipenv && pipenv install --dev
- name: Run coverage - name: Run coverage
run: pipenv run ./scripts/coverage.sh run: pipenv run ./scripts/coverage.sh
# Build # Build

View File

@ -16,11 +16,11 @@ jobs:
- name: Building Docker Image - name: Building Docker Image
run: docker build run: docker build
--no-cache --no-cache
-t beryju/passbook:0.8.11-beta -t beryju/passbook:0.8.14-beta
-t beryju/passbook:latest -t beryju/passbook:latest
-f Dockerfile . -f Dockerfile .
- name: Push Docker Container to Registry (versioned) - name: Push Docker Container to Registry (versioned)
run: docker push beryju/passbook:0.8.11-beta run: docker push beryju/passbook:0.8.14-beta
- name: Push Docker Container to Registry (latest) - name: Push Docker Container to Registry (latest)
run: docker push beryju/passbook:latest run: docker push beryju/passbook:latest
build-gatekeeper: build-gatekeeper:
@ -37,11 +37,11 @@ jobs:
cd gatekeeper cd gatekeeper
docker build \ docker build \
--no-cache \ --no-cache \
-t beryju/passbook-gatekeeper:0.8.11-beta \ -t beryju/passbook-gatekeeper:0.8.14-beta \
-t beryju/passbook-gatekeeper:latest \ -t beryju/passbook-gatekeeper:latest \
-f Dockerfile . -f Dockerfile .
- name: Push Docker Container to Registry (versioned) - name: Push Docker Container to Registry (versioned)
run: docker push beryju/passbook-gatekeeper:0.8.11-beta run: docker push beryju/passbook-gatekeeper:0.8.14-beta
- name: Push Docker Container to Registry (latest) - name: Push Docker Container to Registry (latest)
run: docker push beryju/passbook-gatekeeper:latest run: docker push beryju/passbook-gatekeeper:latest
build-static: build-static:
@ -66,11 +66,11 @@ jobs:
run: docker build run: docker build
--no-cache --no-cache
--network=$(docker network ls | grep github | awk '{print $1}') --network=$(docker network ls | grep github | awk '{print $1}')
-t beryju/passbook-static:0.8.11-beta -t beryju/passbook-static:0.8.14-beta
-t beryju/passbook-static:latest -t beryju/passbook-static:latest
-f static.Dockerfile . -f static.Dockerfile .
- name: Push Docker Container to Registry (versioned) - name: Push Docker Container to Registry (versioned)
run: docker push beryju/passbook-static:0.8.11-beta run: docker push beryju/passbook-static:0.8.14-beta
- name: Push Docker Container to Registry (latest) - name: Push Docker Container to Registry (latest)
run: docker push beryju/passbook-static:latest run: docker push beryju/passbook-static:latest
test-release: test-release:

587
Pipfile.lock generated
View File

@ -25,10 +25,10 @@
}, },
"asgiref": { "asgiref": {
"hashes": [ "hashes": [
"sha256:7e06d934a7718bf3975acbf87780ba678957b87c7adc056f13b6215d610695a0", "sha256:8036f90603c54e93521e5777b2b9a39ba1bad05773fcf2d208f0299d1df58ce5",
"sha256:ea448f92fc35a0ef4b1508f53a04c4670255a3f33d22a81c8fc9c872036adbe5" "sha256:9ca8b952a0a9afa61d30aa6d3d9b570bb3fd6bafcf7ec9e6bed43b936133db1c"
], ],
"version": "==3.2.3" "version": "==3.2.7"
}, },
"asn1crypto": { "asn1crypto": {
"hashes": [ "hashes": [
@ -46,40 +46,40 @@
}, },
"billiard": { "billiard": {
"hashes": [ "hashes": [
"sha256:26fd494dc3251f8ce1f5559744f18aeed427fdaf29a75d7baae26752a5d3816f", "sha256:bff575450859a6e0fbc2f9877d9b715b0bbc07c3565bb7ed2280526a0cdf5ede",
"sha256:f4e09366653aa3cb3ae8ed16423f9ba1665ff426f087bcdbbed86bf3664fe02c" "sha256:d91725ce6425f33a97dfa72fb6bfef0e47d4652acd98a032bd1a7fbf06d5fa6a"
], ],
"version": "==3.6.2.0" "version": "==3.6.3.0"
}, },
"boto3": { "boto3": {
"hashes": [ "hashes": [
"sha256:33462a79d57c9c4a215e075472509537d03545f54566fc4f776fb0f4cfa616f6", "sha256:970bd7b332e73d7b51077ed36772c634811b38c81b0cc6ed0f910e50d7ebadf8",
"sha256:34f9a04f529dc849f0e427782d6f3c6b62f7fb734d8f4859b17e5dee0855323e" "sha256:cdd79a3a7bbe1f33a365f0acfcc75c4405b482b3eb9ce3f4e6b16c418e201ac3"
], ],
"index": "pypi", "index": "pypi",
"version": "==1.12.0" "version": "==1.12.39"
}, },
"botocore": { "botocore": {
"hashes": [ "hashes": [
"sha256:055da4826f6c9158e4a61549d57a2ce449c27d44ce34ab4c96c7bb7b5c993efc", "sha256:94232b44e1540b7e043e220bd43f855400d0a243e926b26b3fb72994e971d518",
"sha256:1f7cecfcd38c7cac17b5386014eb04626d1c7559ee8d8ec1526058cd23f6d1d4" "sha256:e20ba56476b1031ce5ac8e22b59dabc75bd0e03231f124ed6b9ff99fe0b0c96b"
], ],
"version": "==1.15.0" "version": "==1.15.39"
}, },
"celery": { "celery": {
"hashes": [ "hashes": [
"sha256:7c544f37a84a5eadc44cab1aa8c9580dff94636bb81978cdf9bf8012d9ea7d8f", "sha256:108a0bf9018a871620936c33a3ee9f6336a89f8ef0a0f567a9001f4aa361415f",
"sha256:d3363bb5df72d74420986a435449f3c3979285941dff57d5d97ecba352a0e3e2" "sha256:5b4b37e276033fe47575107a2775469f0b721646a08c96ec2c61531e4fe45f2a"
], ],
"index": "pypi", "index": "pypi",
"version": "==4.4.0" "version": "==4.4.2"
}, },
"certifi": { "certifi": {
"hashes": [ "hashes": [
"sha256:017c25db2a153ce562900032d5bc68e9f191e44e9a0f762f373977de9df1fbb3", "sha256:1d987a998c75633c40847cc966fcf5904906c920a7f17ef374f5aa4282abd304",
"sha256:25b64c7da4cd7479594d035c08c2d809eb4aab3a26e5a990ea98cc450c320f1f" "sha256:51fcb31174be6e6664c5f69e3e1691a2d72a1a12e90f872cbdb1567eb47b6519"
], ],
"version": "==2019.11.28" "version": "==2020.4.5.1"
}, },
"cffi": { "cffi": {
"hashes": [ "hashes": [
@ -137,29 +137,27 @@
}, },
"cryptography": { "cryptography": {
"hashes": [ "hashes": [
"sha256:02079a6addc7b5140ba0825f542c0869ff4df9a69c360e339ecead5baefa843c", "sha256:0cacd3ef5c604b8e5f59bf2582c076c98a37fe206b31430d0cd08138aff0986e",
"sha256:1df22371fbf2004c6f64e927668734070a8953362cd8370ddd336774d6743595", "sha256:192ca04a36852a994ef21df13cca4d822adbbdc9d5009c0f96f1d2929e375d4f",
"sha256:369d2346db5934345787451504853ad9d342d7f721ae82d098083e1f49a582ad", "sha256:19ae795137682a9778892fb4390c07811828b173741bce91e30f899424b3934d",
"sha256:3cda1f0ed8747339bbdf71b9f38ca74c7b592f24f65cdb3ab3765e4b02871651", "sha256:1b9b535d6b55936a79dbe4990b64bb16048f48747c76c29713fea8c50eca2acf",
"sha256:44ff04138935882fef7c686878e1c8fd80a723161ad6a98da31e14b7553170c2", "sha256:2a2ad24d43398d89f92209289f15265107928f22a8d10385f70def7a698d6a02",
"sha256:4b1030728872c59687badcca1e225a9103440e467c17d6d1730ab3d2d64bfeff", "sha256:3be7a5722d5bfe69894d3f7bbed15547b17619f3a88a318aab2e37f457524164",
"sha256:58363dbd966afb4f89b3b11dfb8ff200058fbc3b947507675c19ceb46104b48d", "sha256:49870684da168b90110bbaf86140d4681032c5e6a2461adc7afdd93be5634216",
"sha256:6ec280fb24d27e3d97aa731e16207d58bd8ae94ef6eab97249a2afe4ba643d42", "sha256:587f98ce27ac4547177a0c6fe0986b8736058daffe9160dcf5f1bd411b7fbaa1",
"sha256:7270a6c29199adc1297776937a05b59720e8a782531f1f122f2eb8467f9aab4d", "sha256:5aca6f00b2f42546b9bdf11a69f248d1881212ce5b9e2618b04935b87f6f82a1",
"sha256:73fd30c57fa2d0a1d7a49c561c40c2f79c7d6c374cc7750e9ac7c99176f6428e", "sha256:6b744039b55988519cc183149cceb573189b3e46e16ccf6f8c46798bb767c9dc",
"sha256:7f09806ed4fbea8f51585231ba742b58cbcfbfe823ea197d8c89a5e433c7e912", "sha256:6b91cab3841b4c7cb70e4db1697c69f036c8bc0a253edc0baa6783154f1301e4",
"sha256:90df0cc93e1f8d2fba8365fb59a858f51a11a394d64dbf3ef844f783844cc793", "sha256:7598974f6879a338c785c513e7c5a4329fbc58b9f6b9a6305035fca5b1076552",
"sha256:971221ed40f058f5662a604bd1ae6e4521d84e6cad0b7b170564cc34169c8f13", "sha256:7a279f33a081d436e90e91d1a7c338553c04e464de1c9302311a5e7e4b746088",
"sha256:a518c153a2b5ed6b8cc03f7ae79d5ffad7315ad4569b2d5333a13c38d64bd8d7", "sha256:95e1296e0157361fe2f5f0ed307fd31f94b0ca13372e3673fa95095a627636a1",
"sha256:b0de590a8b0979649ebeef8bb9f54394d3a41f66c5584fff4220901739b6b2f0", "sha256:9fc9da390e98cb6975eadf251b6e5fa088820141061bf041cd5c72deba1dc526",
"sha256:b43f53f29816ba1db8525f006fa6f49292e9b029554b3eb56a189a70f2a40879", "sha256:cc20316e3f5a6b582fc3b029d8dc03aabeb645acfcb7fc1d9848841a33265748",
"sha256:d31402aad60ed889c7e57934a03477b572a03af7794fa8fb1780f21ea8f6551f", "sha256:d1bf5a1a0d60c7f9a78e448adcb99aa101f3f9588b16708044638881be15d6bc",
"sha256:de96157ec73458a7f14e3d26f17f8128c959084931e8997b9e655a39c8fde9f9", "sha256:ed1d0760c7e46436ec90834d6f10477ff09475c692ed1695329d324b2c5cd547",
"sha256:df6b4dca2e11865e6cfbfb708e800efb18370f5a46fd601d3755bc7f85b3a8a2", "sha256:ef9a55013676907df6c9d7dd943eb1770d014f68beaa7e73250fb43c759f4585"
"sha256:ecadccc7ba52193963c0475ac9f6fa28ac01e01349a2ca48509667ef41ffd2cf",
"sha256:fb81c17e0ebe3358486cd8cc3ad78adbae58af12fc2bf2bc0bb84e8090fa5ce8"
], ],
"version": "==2.8" "version": "==2.9"
}, },
"defusedxml": { "defusedxml": {
"hashes": [ "hashes": [
@ -171,11 +169,11 @@
}, },
"django": { "django": {
"hashes": [ "hashes": [
"sha256:2f1ba1db8648484dd5c238fb62504777b7ad090c81c5f1fd8d5eb5ec21b5f283", "sha256:642d8eceab321ca743ae71e0f985ff8fdca59f07aab3a9fb362c617d23e33a76",
"sha256:c91c91a7ad6ef67a874a4f76f58ba534f9208412692a840e1d125eb5c279cb0a" "sha256:d4666c2edefa38c5ede0ec1655424c56dc47ceb04b6d8d62a7eac09db89545c1"
], ],
"index": "pypi", "index": "pypi",
"version": "==3.0.3" "version": "==3.0.5"
}, },
"django-cors-middleware": { "django-cors-middleware": {
"hashes": [ "hashes": [
@ -218,10 +216,11 @@
}, },
"django-oauth-toolkit": { "django-oauth-toolkit": {
"hashes": [ "hashes": [
"sha256:ad1b76275950ebbff708222cec57bbdb879f89bac7df6b9dee0f4b9db485c264" "sha256:28508f83385ab4313936ddedfb310eaa8a1dcb737153d2956383ce47e75c2fab",
"sha256:d5a1044af9419ddc048390c5974777ea97874e5b78e33c609e17eebb8423afb2"
], ],
"index": "pypi", "index": "pypi",
"version": "==1.2.0" "version": "==1.3.2"
}, },
"django-oidc-provider": { "django-oidc-provider": {
"hashes": [ "hashes": [
@ -240,11 +239,11 @@
}, },
"django-prometheus": { "django-prometheus": {
"hashes": [ "hashes": [
"sha256:362ea45e5ee26bdba85ce978aeb370659ca6bbc0d6bac69868a055179e053bd1", "sha256:1a8cb752ae4181e38df00e7bd7d5f6495cde18b8b3ff697c22f9d8d2fe48bf28",
"sha256:facaa677386899303ea26c45552371cc43f476e42a81c081011a49cb5564af0b" "sha256:9f024af5495447c8e309f07e5289e7bc1100c5a380ac7cd0afe3a1b2a0b3b534"
], ],
"index": "pypi", "index": "pypi",
"version": "==2.1.0.dev5" "version": "==2.1.0.dev14"
}, },
"django-recaptcha": { "django-recaptcha": {
"hashes": [ "hashes": [
@ -322,16 +321,17 @@
}, },
"idna": { "idna": {
"hashes": [ "hashes": [
"sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", "sha256:7588d1c14ae4c77d74036e8c22ff447b26d0fde8f007354fd48a7814db15b7cb",
"sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c" "sha256:a068a21ceac8a4d63dbfd964670474107f541babbd2250d61922f029858365fa"
], ],
"version": "==2.8" "version": "==2.9"
}, },
"inflection": { "inflection": {
"hashes": [ "hashes": [
"sha256:18ea7fb7a7d152853386523def08736aa8c32636b047ade55f7578c4edeb16ca" "sha256:32a5c3341d9583ec319548b9015b7fbdf8c429cbcb575d326c33ae3a0e90d52c",
"sha256:9a15d3598f01220e93f2207c432cfede50daff53137ce660fb8be838ef1ca6cc"
], ],
"version": "==0.3.1" "version": "==0.4.0"
}, },
"itypes": { "itypes": {
"hashes": [ "hashes": [
@ -349,10 +349,10 @@
}, },
"jmespath": { "jmespath": {
"hashes": [ "hashes": [
"sha256:3720a4b1bd659dd2eecad0666459b9788813e032b83e7ba58578e48254e0a0e6", "sha256:695cb76fa78a10663425d5b73ddc5714eb711157e52704d69be03b1a02ba4fec",
"sha256:bde2aef6f44302dfb30320115b17d030798de8c4110e28d5cf6cf91a7a31074c" "sha256:cca55c8d153173e21baa59983015ad0daf603f9cb799904ff057bfb8ff8dc2d9"
], ],
"version": "==0.9.4" "version": "==0.9.5"
}, },
"jsonschema": { "jsonschema": {
"hashes": [ "hashes": [
@ -363,19 +363,19 @@
}, },
"kombu": { "kombu": {
"hashes": [ "hashes": [
"sha256:2a9e7adff14d046c9996752b2c48b6d9185d0b992106d5160e1a179907a5d4ac", "sha256:2d1cda774126a044d91a7ff5fa6d09edf99f46924ab332a810760fe6740e9b76",
"sha256:67b32ccb6fea030f8799f8fd50dd08e03a4b99464ebc4952d71d8747b1a52ad1" "sha256:598e7e749d6ab54f646b74b2d2df67755dee13894f73ab02a2a9feb8870c7cb2"
], ],
"index": "pypi", "index": "pypi",
"version": "==4.6.7" "version": "==4.6.8"
}, },
"ldap3": { "ldap3": {
"hashes": [ "hashes": [
"sha256:1898194d872539670a2f36d4b56fe5a35d4b9ead28103bec78f05a8993e8122f", "sha256:17f04298b70bf7ecaa5db8a7d8622b5a962ef7fc2b245b2eea705ac1c24338c0",
"sha256:27cb673e7afcb539f6adcae5a3ecac4e74eb37ca0a2d50dc98f29a3829eee529" "sha256:81df4ac8b6df10fb1f05b17c18d0cb8c4c344d5a03083c382824960ed959cf5b"
], ],
"index": "pypi", "index": "pypi",
"version": "==2.6.1" "version": "==2.7"
}, },
"lxml": { "lxml": {
"hashes": [ "hashes": [
@ -458,11 +458,11 @@
}, },
"packaging": { "packaging": {
"hashes": [ "hashes": [
"sha256:170748228214b70b672c581a3dd610ee51f733018650740e98c7df862a583f73", "sha256:3c292b474fda1671ec57d46d739d072bfd495a4f51ad01a055121d81e952b7a3",
"sha256:e665345f9eef0c621aa0bf2f8d78cf6d21904eef16a93f020240b704a57f1334" "sha256:82f77b9bee21c1bafbf35a84905d604d5d1223801d639cf3ed140bd651c08752"
], ],
"index": "pypi", "index": "pypi",
"version": "==20.1" "version": "==20.3"
}, },
"prometheus-client": { "prometheus-client": {
"hashes": [ "hashes": [
@ -472,41 +472,39 @@
}, },
"psycopg2-binary": { "psycopg2-binary": {
"hashes": [ "hashes": [
"sha256:040234f8a4a8dfd692662a8308d78f63f31a97e1c42d2480e5e6810c48966a29", "sha256:008da3ab51adc70a5f1cfbbe5db3a22607ab030eb44bcecf517ad11a0c2b3cac",
"sha256:086f7e89ec85a6704db51f68f0dcae432eff9300809723a6e8782c41c2f48e03", "sha256:07cf82c870ec2d2ce94d18e70c13323c89f2f2a2628cbf1feee700630be2519a",
"sha256:18ca813fdb17bc1db73fe61b196b05dd1ca2165b884dd5ec5568877cabf9b039", "sha256:08507efbe532029adee21b8d4c999170a83760d38249936038bd0602327029b5",
"sha256:19dc39616850342a2a6db70559af55b22955f86667b5f652f40c0e99253d9881", "sha256:107d9be3b614e52a192719c6bf32e8813030020ea1d1215daa86ded9a24d8b04",
"sha256:2166e770cb98f02ed5ee2b0b569d40db26788e0bf2ec3ae1a0d864ea6f1d8309", "sha256:17a0ea0b0eabf07035e5e0d520dabc7950aeb15a17c6d36128ba99b2721b25b1",
"sha256:3a2522b1d9178575acee4adf8fd9f979f9c0449b00b4164bb63c3475ea6528ed", "sha256:3286541b9d85a340ee4ed42732d15fc1bb441dc500c97243a768154ab8505bb5",
"sha256:3aa773580f85a28ffdf6f862e59cb5a3cc7ef6885121f2de3fca8d6ada4dbf3b", "sha256:3939cf75fc89c5e9ed836e228c4a63604dff95ad19aed2bbf71d5d04c15ed5ce",
"sha256:3b5deaa3ee7180585a296af33e14c9b18c218d148e735c7accf78130765a47e3", "sha256:40abc319f7f26c042a11658bf3dd3b0b3bceccf883ec1c565d5c909a90204434",
"sha256:407af6d7e46593415f216c7f56ba087a9a42bd6dc2ecb86028760aa45b802bd7", "sha256:51f7823f1b087d2020d8e8c9e6687473d3d239ba9afc162d9b2ab6e80b53f9f9",
"sha256:4c3c09fb674401f630626310bcaf6cd6285daf0d5e4c26d6e55ca26a2734e39b", "sha256:6bb2dd006a46a4a4ce95201f836194eb6a1e863f69ee5bab506673e0ca767057",
"sha256:4c6717962247445b4f9e21c962ea61d2e884fc17df5ddf5e35863b016f8a1f03", "sha256:702f09d8f77dc4794651f650828791af82f7c2efd8c91ae79e3d9fe4bb7d4c98",
"sha256:50446fae5681fc99f87e505d4e77c9407e683ab60c555ec302f9ac9bffa61103", "sha256:7036ccf715925251fac969f4da9ad37e4b7e211b1e920860148a10c0de963522",
"sha256:5057669b6a66aa9ca118a2a860159f0ee3acf837eda937bdd2a64f3431361a2d", "sha256:7b832d76cc65c092abd9505cc670c4e3421fd136fb6ea5b94efbe4c146572505",
"sha256:5dd90c5438b4f935c9d01fcbad3620253da89d19c1f5fca9158646407ed7df35", "sha256:8f74e631b67482d504d7e9cf364071fc5d54c28e79a093ff402d5f8f81e23bfa",
"sha256:659c815b5b8e2a55193ede2795c1e2349b8011497310bb936da7d4745652823b", "sha256:930315ac53dc65cbf52ab6b6d27422611f5fb461d763c531db229c7e1af6c0b3",
"sha256:69b13fdf12878b10dc6003acc8d0abf3ad93e79813fd5f3812497c1c9fb9be49", "sha256:96d3038f5bd061401996614f65d27a4ecb62d843eb4f48e212e6d129171a721f",
"sha256:7a1cb80e35e1ccea3e11a48afe65d38744a0e0bde88795cc56a4d05b6e4f9d70", "sha256:a20299ee0ea2f9cca494396ac472d6e636745652a64a418b39522c120fd0a0a4",
"sha256:7e6e3c52e6732c219c07bd97fff6c088f8df4dae3b79752ee3a817e6f32e177e", "sha256:a34826d6465c2e2bbe9d0605f944f19d2480589f89863ed5f091943be27c9de4",
"sha256:7f42a8490c4fe854325504ce7a6e4796b207960dabb2cbafe3c3959cb00d1d7e", "sha256:a69970ee896e21db4c57e398646af9edc71c003bc52a3cc77fb150240fefd266",
"sha256:84156313f258eafff716b2961644a4483a9be44a5d43551d554844d15d4d224e", "sha256:b9a8b391c2b0321e0cd7ec6b4cfcc3dd6349347bd1207d48bcb752aa6c553a66",
"sha256:8578d6b8192e4c805e85f187bc530d0f52ba86c39172e61cd51f68fddd648103", "sha256:ba13346ff6d3eb2dca0b6fa0d8a9d999eff3dcd9b55f3a890f12b0b6362b2b38",
"sha256:890167d5091279a27e2505ff0e1fb273f8c48c41d35c5b92adbf4af80e6b2ed6", "sha256:bb0608694a91db1e230b4a314e8ed00ad07ed0c518f9a69b83af2717e31291a3",
"sha256:98e10634792ac0e9e7a92a76b4991b44c2325d3e7798270a808407355e7bb0a1", "sha256:c8830b7d5f16fd79d39b21e3d94f247219036b29b30c8270314c46bf8b732389",
"sha256:9aadff9032e967865f9778485571e93908d27dab21d0fdfdec0ca779bb6f8ad9", "sha256:cac918cd7c4c498a60f5d2a61d4f0a6091c2c9490d81bc805c963444032d0dab",
"sha256:9f24f383a298a0c0f9b3113b982e21751a8ecde6615494a3f1470eb4a9d70e9e", "sha256:cc30cb900f42c8a246e2cb76539d9726f407330bc244ca7729c41a44e8d807fb",
"sha256:a73021b44813b5c84eda4a3af5826dd72356a900bac9bd9dd1f0f81ee1c22c2f", "sha256:ccdc6a87f32b491129ada4b87a43b1895cf2c20fdb7f98ad979647506ffc41b6",
"sha256:afd96845e12638d2c44d213d4810a08f4dc4a563f9a98204b7428e567014b1cd", "sha256:d1a8b01f6a964fec702d6b6dac1f91f2b9f9fe41b310cbb16c7ef1fac82df06d",
"sha256:b73ddf033d8cd4cc9dfed6324b1ad2a89ba52c410ef6877998422fcb9c23e3a8", "sha256:e004db88e5a75e5fdab1620fb9f90c9598c2a195a594225ac4ed2a6f1c23e162",
"sha256:b8f490f5fad1767a1331df1259763b3bad7d7af12a75b950c2843ba319b2415f", "sha256:eb2f43ae3037f1ef5e19339c41cf56947021ac892f668765cd65f8ab9814192e",
"sha256:dbc5cd56fff1a6152ca59445178652756f4e509f672e49ccdf3d79c1043113a4", "sha256:fa466306fcf6b39b8a61d003123d442b23707d635a5cb05ac4e1b62cc79105cd"
"sha256:eac8a3499754790187bb00574ab980df13e754777d346f85e0ff6df929bcd964",
"sha256:eaed1c65f461a959284649e37b5051224f4db6ebdc84e40b5e65f2986f101a08"
], ],
"index": "pypi", "index": "pypi",
"version": "==2.8.4" "version": "==2.8.5"
}, },
"pyasn1": { "pyasn1": {
"hashes": [ "hashes": [
@ -524,80 +522,81 @@
}, },
"pycparser": { "pycparser": {
"hashes": [ "hashes": [
"sha256:a988718abfad80b6b157acce7bf130a30876d27603738ac39f140993246b25b3" "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0",
"sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"
], ],
"version": "==2.19" "version": "==2.20"
}, },
"pycryptodome": { "pycryptodome": {
"hashes": [ "hashes": [
"sha256:012ca77c2105600e3c6aef43188101ac1d95052c633a4ae8fbebffab20c25f8a", "sha256:07024fc364869eae8d6ac0d316e089956e6aeffe42dbdcf44fe1320d96becf7f",
"sha256:05b4d865710f9a6378d3ada28195ff78e52642d3ecffe6fa9d379d870b9bf29d", "sha256:09b6d6bcc01a4eb1a2b4deeff5aa602a108ec5aed8ac75ae554f97d1d7f0a5ad",
"sha256:07daddb98f98f771ba027f8f835bdb675aeb84effe41ed5221f520b267429354", "sha256:0e10f352ccbbcb5bb2dc4ecaf106564e65702a717d72ab260f9ac4c19753cfc2",
"sha256:09bf05a489fe10f9280a5e0163f195e7b9630cafb15f7d72fb9c8f5eb2afa84f", "sha256:1f4752186298caf2e9ff5354f2e694d607ca7342aa313a62005235d46e28cf04",
"sha256:0a8d5f2dbb4bbe830ace54286b829bfa529f0853bedaab6225fcb2e6d1f7e356", "sha256:2fbc472e0b567318fe2052281d5a8c0ae70099b446679815f655e9fbc18c3a65",
"sha256:1259b8ca49662b8a941177357f08147d858595c0042e63ff81e9628e925b5c9d", "sha256:3ec3dc2f80f71fd0c955ce48b81bfaf8914c6f63a41a738f28885a1c4892968a",
"sha256:238d8b6dd27bd1a04816a68aa90a739e6dd23b192fcd83b50f9360958bff192a", "sha256:426c188c83c10df71f053e04b4003b1437bae5cb37606440e498b00f160d71d0",
"sha256:2a57daef18a2022a5e4b6f7376c9ddd0c2d946e4b1f1e59b837f5bf295be7380", "sha256:626c0a1d4d83ec6303f970a17158114f75c3ba1736f7f2983f7b40a265861bd8",
"sha256:39e5ca2f66d1eac7abcba5ce1a03370d123dc6085620f1cd532dfee27e650178", "sha256:767ad0fb5d23efc36a4d5c2fc608ac603f3de028909bcf59abc943e0d0bc5a36",
"sha256:3d516df693c195b8da3795e381429bd420e87081b7e6c2871c62c9897c812cda", "sha256:7ac729d9091ed5478af2b4a4f44f5335a98febbc008af619e4569a59fe503e40",
"sha256:3e486c5b7228e864665fc479e9f596b2547b5fe29c6f5c8ed3807784d06faed7", "sha256:83295a3fb5cf50c48631eb5b440cb5e9832d8c14d81d1d45f4497b67a9987de8",
"sha256:5029c46b0d41dfb763c3981c0af68eab029f06fe2b94f2299112fc18cf9e8d6d", "sha256:8be56bde3312e022d9d1d6afa124556460ad5c844c2fc63642f6af723c098d35",
"sha256:5817c0b3c263025d851da96b90cbc7e95348008f88b990e90d10683dba376666", "sha256:8f06556a8f7ea7b1e42eff39726bb0dca1c251205debae64e6eebea3cd7b438a",
"sha256:79320f1fc5c9ca682869087c565bb29ca6f334692e940d7365771e9a94382e12", "sha256:9230fcb5d948c3fb40049bace4d33c5d254f8232c2c0bba05d2570aea3ba4520",
"sha256:887d08beca6368d3d70dc75126607ad76317a9fd07fe61323d8c3cb42add12b6", "sha256:9378c309aec1f8cd8bad361ed0816a440151b97a2a3f6ffdaba1d1a1fb76873a",
"sha256:9163fec630495c10c767991e3f8dab32f4427bfb2dfeaa59bb28fe3e52ba66f2", "sha256:9977086e0f93adb326379897437373871b80501e1d176fec63c7f46fb300c862",
"sha256:95d324e603c5cec5d89e8595236bbf59ade5fe3a72d100ce61eebb323d598750", "sha256:9a94fca11fdc161460bd8659c15b6adef45c1b20da86402256eaf3addfaab324",
"sha256:9927aa8a8cb4af681279b6f28a1dcb14e0eb556c1aea8413a1e27608a8516e0c", "sha256:9c739b7795ccf2ef1fdad8d44e539a39ad300ee6786e804ea7f0c6a786eb5343",
"sha256:9948c2d5c5c0ee45ed44cee0e2eba2ce60a03be006ed3074521f3da3be162e72", "sha256:b1e332587b3b195542e77681389c296e1837ca01240399d88803a075447d3557",
"sha256:a719bd708207fa219fcbf4c8ebbcbc52846045f78179d00445b429fdabdbc1c4", "sha256:c109a26a21f21f695d369ff9b87f5d43e0d6c768d8384e10bc74142bed2e092e",
"sha256:bc22ced26ebc46546798fa0141f4418f1db116dec517f0aeaecec87cf7b2416c", "sha256:c818dc1f3eace93ee50c2b6b5c2becf7c418fa5dd1ba6fc0ef7db279ea21d5e4",
"sha256:c41b7e10b72cef00cd63410f31fe50e72dc3a40eafbd146e288384fbe4208064", "sha256:cff31f5a8977534f255f729d5d2467526f2b10563a30bbdade92223e0bf264bd",
"sha256:cdb0ad83a5d6bac986a37fcb7562bcbef0aabae8ea19505bab5cf83c4d18af12", "sha256:d4f94368ce2d65873a87ad867eb3bf63f4ba81eb97a9ee66d38c2b71ce5a7439",
"sha256:d8e480f65ac7105cbc288eec2417dc61eaac6ed6e75595aa15b8c7c77c53a68b", "sha256:d61b012baa8c2b659e9890011358455c0019a4108536b811602d2f638c40802a",
"sha256:da2d581da279bc7408d38e16ff77754f5448c4352f2acfe530a5d14d8fc6934a", "sha256:d6e1bc5c94873bec742afe2dfadce0d20445b18e75c47afc0c115b19e5dd38dd",
"sha256:de61091dd68326b600422cf731eb4810c4c6363f18a65bccd6061784b7454f5b", "sha256:ea83bcd9d6c03248ebd46e71ac313858e0afd5aa2fa81478c0e653242f3eb476",
"sha256:ec7d39589f9cfc2a8b83b1d2fc673441757c99d43283e97b2dd46e0e23730db8", "sha256:ed5761b37615a1f222c5345bbf45272ae2cf8c7dff88a4f53a1e9f977cbb6d95",
"sha256:f3204006869ab037604b1d9f045c4e84882ddd365e4ee8caa5eb1ff47a59188e", "sha256:f011cd0062e54658b7086a76f8cf0f4222812acc66e219e196ea2d0a8849d0ed",
"sha256:f4d2174e168d0eabd1fffaf88b4f62c2b6f30a67b8816f31024b8e48be3e2d75", "sha256:f1add21b6d179179b3c177c33d18a2186a09cc0d3af41ff5ed3f377360b869f2",
"sha256:fcff8c9d88d58880f7eda2139c7c444552a38f98a9e77ba5970b6e78f54ac358" "sha256:f655addaaaa9974108d4808f4150652589cada96074c87115c52e575bfcd87d5"
], ],
"index": "pypi", "index": "pypi",
"version": "==3.9.6" "version": "==3.9.7"
}, },
"pycryptodomex": { "pycryptodomex": {
"hashes": [ "hashes": [
"sha256:04646e40ef5788bad6d415e52862ffcdf2ac2d888ba4a5c82d5cb44607a042f7", "sha256:1537d2d15b604b303aef56e7f440895a1c81adbee786b91f1f06eddc34da5314",
"sha256:132f1e5fa84921f25695a313a6d4988847dfaee7fb1fd0d1fbe03ef678836f58", "sha256:1d20ab8369b7558168fc014a0745c678613f9f486dae468cca2d68145196b8a4",
"sha256:17ad1ebaa00806305d34550fe5d3c776e38a27b8a2678dfb7871ef0209d64e46", "sha256:1ecc9db7409db67765eb008e558879d298406642d33ade43a6488224d23e8081",
"sha256:27736fa02a2d3502e1ca4b150457e56ce3b98f132462f540073498884e5f8975", "sha256:37033976f72af829fe15f7fe5fe1dbed308cc43a98d9dd9d2a0a76de8ca5ee78",
"sha256:38050b3fd86c74c6c79e40bbe824bec6431c3e4e36f6080ed544673ba2dc133a", "sha256:3c3dd9d4c9c1e279d3945ae422895c901f98987333acc132dc094faf52afec35",
"sha256:3b9306b360bddbc8e098b16eab7adacf49389d212db9c3739588ab840a1ca868", "sha256:3c9b3fba037ea52c626060c5a87ee6de7e86c99e8a7c6ee07302539985d2bd64",
"sha256:466e36ba74a7e725625e717fad3f36e0b9293c247b7d0439c66528026ef2834f", "sha256:45ee555fc5e28c119a46d44ce373f5237e54a35c61b750fb3a94446b09855dbc",
"sha256:4f77360b23a21db32a4c35dacffac33dc30ac6a5a77162a34e99ab11ab631516", "sha256:4c93038ac011b36512cb0bf2ee3e2aec774e8bc81021d015917c89fe02bb0ee5",
"sha256:5002388178845683c330a02f4faeddfe7cd477b87824987cca4718fa0c4f2085", "sha256:50163324834edd0c9ce3e4512ded3e221c969086e10fdd5d3fdcaadac5e24a78",
"sha256:51be76756abfc1ddc97e1e2e3c38f4e62fb940161162368308ea9e5919e86c34", "sha256:59b0ea9cda5490f924771456912a225d8d9e678891f9f986661af718534719b2",
"sha256:544628ae67d61c31c28a60e621dadd738b303c5266492355d5ebdb6e7dd1e78f", "sha256:5cf306a17cccc327a33cdc3845629fa13f4573a4ec620ed607c79cf6785f2e27",
"sha256:6ff9d4a06bc40211eee05cd88436740d698a01233f4aaff9eb70d8a90e578966", "sha256:5fff8da399af16a1855f58771223acbbdac720b9969cd03fc5013d2e9a7bd9a4",
"sha256:718329c6ca60260f1c27b8392e372dd51e4e691f7dcb88adc53eb3b76af6363c", "sha256:68650ce5b9f7152b8283302a4617269f821695a612692640dd247bd12ab21c0b",
"sha256:918bc5a0170fe8ed7b72f202245b34f84a1997f5ca1520b9c7db71126e5acd62", "sha256:6b3a9a562688996f760b5077714c3ab8b62ca56061b6e9ab7906841e43e19f91",
"sha256:a8ea72adde0d010f89abece5f024b1be95a5c52472e9a57b3ac7d59aee3c8238", "sha256:7e938ed51a59e29431ea86fab60423ada2757728db0f78952329fa02a789bd31",
"sha256:a979d2c7bcc67282b7ec2600db384c63d37d74e250edb99168483605a380bf62", "sha256:87aa70daad6f039e814790a06422a3189311198b674b62f13933a2bdcb6b1bcc",
"sha256:b350f9ad09b692aed57e669fc3f8cf918557fae9f0229c6ce9286a6fe8c1b60f", "sha256:99be3a1df2b2b9f731ebe1c264a2c07c465e71cee68e35e1640b645b5213a755",
"sha256:be838abc8557a21a60d453c5a4e64c738966b8a0b7d7f8f97eb8bb44041ca452", "sha256:a3f2908666e6f74b8c4893f86dd02e16170f50e4a78ae7f3468b6208d54bc205",
"sha256:bfa99692d3c8f994c5850cc8a894cba001abd76d34069a8bfaad173dd46387d6", "sha256:ae3d44a639fd11dbdeca47e35e94febb1ee8bc15daf26673331add37146e0b85",
"sha256:c021b66f5b3c4ea0c45422ec3241bfea4a16651e1ee5459a136639d0716ccb3c", "sha256:afb4c2fa3c6f492fd9a8b38d76e13f32d429b8e5e1e00238309391b5591cde0d",
"sha256:c7babb64484080057a24c74a82dbf7997904b1710b74caf62e261610f989b437", "sha256:b1515ce3a8a2c3fa537d137c5ca5f8b7a902044d04e07d7c3aa26c3e026120fb",
"sha256:c96b7762b601dc8a58d7712235c3c152868116f58a7ffa40dcd1c6f6cd97405e", "sha256:bf391b377413a197000b43ef2b74359974d8927d329a897c9f5ba7b63dca7b9c",
"sha256:d67b6e0bae0777a2c6c83275fbd7cbf53cd5f23c2028f908b0f7d996466e5b15", "sha256:c436919117c23355740c669f89720673578b9aa4569bbfe105f6c10101fc1966",
"sha256:e15f39fcfb949cfd5536cc9647daba942b1a99b67e4d7211e3bdbcedbc2f823c", "sha256:d2c3c280975638e2a2c2fd9cb36ab111980219757fa163a2755594b9448e4138",
"sha256:e380448f1e39736f6230ec284cd6d771956ad802d6ce5bc56947a2481080cac1", "sha256:e585d530764c459cbd5d460aed0288807bb881f376ca9a20e653645217895961",
"sha256:e5236f2171b21e704d1854fd809a7228eb22e29c894af31459e41986e6a53f87", "sha256:e76e6638ead4a7d93262a24218f0ff3ff74de6b6c823b7e19dccb31b6a481978",
"sha256:ea7b48ce8dbbc86ebadcfe56ebc10d413bdd12c9a5ff0b9147a41993f12b80b3", "sha256:ebfc2f885cafda076c31ae30fa0dd81e7e919ec34059a88d3018ed66e83fcce3",
"sha256:f39f5b58d8fe348ed604bb44a89ca93b26130c275db2b249f718f1538cb70500", "sha256:f5797a39933a3d41526da60856735e6684b2b71a8ca99d5f79555ca121be2f4b",
"sha256:f545f776e45f74c41329e4020463fdd4d0cd0a7501bdf9e50251dafe7bd959a9", "sha256:f7e5fc5e124200b19a14be33fb0099e956e6ebb5e25d287b0829ef0a78ed76c7",
"sha256:f667ac7ae29c19530f199854635f1a97e73d0bfd24163e0db6bdba7dba04eb9f" "sha256:fb350e31e55211fec8ddc89fc0256f3b9bc3b44b68a8bde1cf44b3b4e80c0e42"
], ],
"version": "==3.9.6" "version": "==3.9.7"
}, },
"pyjwkest": { "pyjwkest": {
"hashes": [ "hashes": [
@ -614,16 +613,16 @@
}, },
"pyparsing": { "pyparsing": {
"hashes": [ "hashes": [
"sha256:4c830582a84fb022400b85429791bc551f1f4871c33f23e44f353119e92f969f", "sha256:67199f0c41a9c702154efb0e7a8cc08accf830eb003b4d9fa42c4059002e2492",
"sha256:c342dccb5250c08d45fd6f8b4a559613ca603b57498511740e65cd11a2e7dcec" "sha256:700d17888d441604b0bd51535908dcb297561b040819cccde647a92439db5a2a"
], ],
"version": "==2.4.6" "version": "==3.0.0a1"
}, },
"pyrsistent": { "pyrsistent": {
"hashes": [ "hashes": [
"sha256:cdc7b5e3ed77bed61270a47d35434a30617b9becdf2478af76ad2c6ade307280" "sha256:28669905fe725965daa16184933676547c5bb40a5153055a8dee2a4bd7933ad3"
], ],
"version": "==0.15.7" "version": "==0.16.0"
}, },
"python-dateutil": { "python-dateutil": {
"hashes": [ "hashes": [
@ -673,20 +672,20 @@
}, },
"pyyaml": { "pyyaml": {
"hashes": [ "hashes": [
"sha256:059b2ee3194d718896c0ad077dd8c043e5e909d9180f387ce42012662a4946d6", "sha256:06a0d7ba600ce0b2d2fe2e78453a470b5a6e000a985dd4a4e54e436cc36b0e97",
"sha256:1cf708e2ac57f3aabc87405f04b86354f66799c8e62c28c5fc5f88b5521b2dbf", "sha256:240097ff019d7c70a4922b6869d8a86407758333f02203e0fc6ff79c5dcede76",
"sha256:24521fa2890642614558b492b473bee0ac1f8057a7263156b02e8b14c88ce6f5", "sha256:4f4b913ca1a7319b33cfb1369e91e50354d6f07a135f3b901aca02aa95940bd2",
"sha256:4fee71aa5bc6ed9d5f116327c04273e25ae31a3020386916905767ec4fc5317e", "sha256:69f00dca373f240f842b2931fb2c7e14ddbacd1397d57157a9b005a6a9942648",
"sha256:70024e02197337533eef7b85b068212420f950319cc8c580261963aefc75f811", "sha256:73f099454b799e05e5ab51423c7bcf361c58d3206fa7b0d555426b1f4d9a3eaf",
"sha256:74782fbd4d4f87ff04159e986886931456a1894c61229be9eaf4de6f6e44b99e", "sha256:74809a57b329d6cc0fdccee6318f44b9b8649961fa73144a98735b0aaf029f1f",
"sha256:940532b111b1952befd7db542c370887a8611660d2b9becff75d39355303d82d", "sha256:7739fc0fa8205b3ee8808aea45e968bc90082c10aef6ea95e855e10abf4a37b2",
"sha256:cb1f2f5e426dc9f07a7681419fe39cee823bb74f723f36f70399123f439e9b20", "sha256:95f71d2af0ff4227885f7a6605c37fd53d3a106fcab511b8860ecca9fcf400ee",
"sha256:dbbb2379c19ed6042e8f11f2a2c66d39cceb8aeace421bfc29d085d93eda3689", "sha256:b8eac752c5e14d3eca0e6dd9199cd627518cb5ec06add0de9d32baeee6fe645d",
"sha256:e3a057b7a64f1222b56e47bcff5e4b94c4f61faac04c7c4ecb1985e18caa3994", "sha256:cc8955cfbfc7a115fa81d85284ee61147059a753344bc51098f3ccd69b0d7e0c",
"sha256:e9f45bd5b92c7974e59bcd2dcc8631a6b6cc380a904725fce7bc08872e691615" "sha256:d13155f591e6fcc1ec3b30685d50bf0711574e2c0dfffd7644babf8b5102ca1a"
], ],
"index": "pypi", "index": "pypi",
"version": "==5.3" "version": "==5.3.1"
}, },
"qrcode": { "qrcode": {
"hashes": [ "hashes": [
@ -705,10 +704,10 @@
}, },
"requests": { "requests": {
"hashes": [ "hashes": [
"sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4", "sha256:43999036bfa82904b6af1d99e4882b560e5e2c68e5c4b0aa03b655f3d7d73fee",
"sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31" "sha256:b3f43d496c6daba4493e7c431722aeb7dbc6288f52a6e04e7b6023b0247817e6"
], ],
"version": "==2.22.0" "version": "==2.23.0"
}, },
"requests-oauthlib": { "requests-oauthlib": {
"hashes": [ "hashes": [
@ -759,11 +758,11 @@
}, },
"sentry-sdk": { "sentry-sdk": {
"hashes": [ "hashes": [
"sha256:b06dd27391fd11fb32f84fe054e6a64736c469514a718a99fb5ce1dff95d6b28", "sha256:23808d571d2461a4ce3784ec12bbee5bdb8c026c143fe79d36cef8a6d653e71f",
"sha256:e023da07cfbead3868e1e2ba994160517885a32dfd994fc455b118e37989479b" "sha256:bb90a4e19c7233a580715fc986cc44be2c48fc10b31e71580a2037e1c94b6950"
], ],
"index": "pypi", "index": "pypi",
"version": "==0.14.1" "version": "==0.14.3"
}, },
"service-identity": { "service-identity": {
"hashes": [ "hashes": [
@ -790,10 +789,10 @@
}, },
"sqlparse": { "sqlparse": {
"hashes": [ "hashes": [
"sha256:40afe6b8d4b1117e7dff5504d7a8ce07d9a1b15aeeade8a2d10f130a834f8177", "sha256:022fb9c87b524d1f7862b3037e541f68597a730a8843245c349fc93e1643dc4e",
"sha256:7c3dca29c022744e95b547e867cee89f4fce4373f3549ccd8797d8eb52cdb873" "sha256:e162203737712307dfe78860cc56c8da8a852ab2ee33750e33aeadf38d12c548"
], ],
"version": "==0.3.0" "version": "==0.3.1"
}, },
"structlog": { "structlog": {
"hashes": [ "hashes": [
@ -805,11 +804,11 @@
}, },
"swagger-spec-validator": { "swagger-spec-validator": {
"hashes": [ "hashes": [
"sha256:57e29feb3aa921a9fb98bd70af148746b27c77d3207266f5571cebcce211e685", "sha256:61f2d2a732b886cf33c2c24886565be9692e5814cacc17fd973e095b72b33e4f",
"sha256:62ef22eca3f429d93fddda5d793d2a1a9057d3732e7a14606e641805326ae4a6" "sha256:8eb82682871f8d63067b455e2e055c8dd953ca260e791635b58dfe0b73ba1f43"
], ],
"index": "pypi", "index": "pypi",
"version": "==2.4.3" "version": "==2.5.0"
}, },
"uritemplate": { "uritemplate": {
"hashes": [ "hashes": [
@ -848,10 +847,10 @@
}, },
"asgiref": { "asgiref": {
"hashes": [ "hashes": [
"sha256:7e06d934a7718bf3975acbf87780ba678957b87c7adc056f13b6215d610695a0", "sha256:8036f90603c54e93521e5777b2b9a39ba1bad05773fcf2d208f0299d1df58ce5",
"sha256:ea448f92fc35a0ef4b1508f53a04c4670255a3f33d22a81c8fc9c872036adbe5" "sha256:9ca8b952a0a9afa61d30aa6d3d9b570bb3fd6bafcf7ec9e6bed43b936133db1c"
], ],
"version": "==3.2.3" "version": "==3.2.7"
}, },
"astroid": { "astroid": {
"hashes": [ "hashes": [
@ -869,10 +868,10 @@
}, },
"autopep8": { "autopep8": {
"hashes": [ "hashes": [
"sha256:0f592a0447acea0c2b0a9602be1e4e3d86db52badd2e3c84f0193bfd89fd3a43" "sha256:cc6be1dfd46f2c7fa00e84a357f1a269683985b09eaffb47654ed551194399eb"
], ],
"index": "pypi", "index": "pypi",
"version": "==1.5" "version": "==1.5.1"
}, },
"bandit": { "bandit": {
"hashes": [ "hashes": [
@ -900,10 +899,10 @@
}, },
"click": { "click": {
"hashes": [ "hashes": [
"sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13", "sha256:8a18b4ea89d8820c5d0c7da8a64b2c324b4dabb695804dbfea19b9be9d88c0cc",
"sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7" "sha256:e345d143d80bf5ee7534056164e5e112ea5e22716bbb1ce727941f4c8b471b9a"
], ],
"version": "==7.0" "version": "==7.1.1"
}, },
"colorama": { "colorama": {
"hashes": [ "hashes": [
@ -915,48 +914,48 @@
}, },
"coverage": { "coverage": {
"hashes": [ "hashes": [
"sha256:15cf13a6896048d6d947bf7d222f36e4809ab926894beb748fc9caa14605d9c3", "sha256:03f630aba2b9b0d69871c2e8d23a69b7fe94a1e2f5f10df5049c0df99db639a0",
"sha256:1daa3eceed220f9fdb80d5ff950dd95112cd27f70d004c7918ca6dfc6c47054c", "sha256:046a1a742e66d065d16fb564a26c2a15867f17695e7f3d358d7b1ad8a61bca30",
"sha256:1e44a022500d944d42f94df76727ba3fc0a5c0b672c358b61067abb88caee7a0", "sha256:0a907199566269e1cfa304325cc3b45c72ae341fbb3253ddde19fa820ded7a8b",
"sha256:25dbf1110d70bab68a74b4b9d74f30e99b177cde3388e07cc7272f2168bd1477", "sha256:165a48268bfb5a77e2d9dbb80de7ea917332a79c7adb747bd005b3a07ff8caf0",
"sha256:3230d1003eec018ad4a472d254991e34241e0bbd513e97a29727c7c2f637bd2a", "sha256:1b60a95fc995649464e0cd48cecc8288bac5f4198f21d04b8229dc4097d76823",
"sha256:3dbb72eaeea5763676a1a1efd9b427a048c97c39ed92e13336e726117d0b72bf", "sha256:1f66cf263ec77af5b8fe14ef14c5e46e2eb4a795ac495ad7c03adc72ae43fafe",
"sha256:5012d3b8d5a500834783689a5d2292fe06ec75dc86ee1ccdad04b6f5bf231691", "sha256:2e08c32cbede4a29e2a701822291ae2bc9b5220a971bba9d1e7615312efd3037",
"sha256:51bc7710b13a2ae0c726f69756cf7ffd4362f4ac36546e243136187cfcc8aa73", "sha256:3844c3dab800ca8536f75ae89f3cf566848a3eb2af4d9f7b1103b4f4f7a5dad6",
"sha256:527b4f316e6bf7755082a783726da20671a0cc388b786a64417780b90565b987", "sha256:408ce64078398b2ee2ec08199ea3fcf382828d2f8a19c5a5ba2946fe5ddc6c31",
"sha256:722e4557c8039aad9592c6a4213db75da08c2cd9945320220634f637251c3894", "sha256:443be7602c790960b9514567917af538cac7807a7c0c0727c4d2bbd4014920fd",
"sha256:76e2057e8ffba5472fd28a3a010431fd9e928885ff480cb278877c6e9943cc2e", "sha256:4482f69e0701139d0f2c44f3c395d1d1d37abd81bfafbf9b6efbe2542679d892",
"sha256:77afca04240c40450c331fa796b3eab6f1e15c5ecf8bf2b8bee9706cd5452fef", "sha256:4a8a259bf990044351baf69d3b23e575699dd60b18460c71e81dc565f5819ac1",
"sha256:7afad9835e7a651d3551eab18cbc0fdb888f0a6136169fbef0662d9cdc9987cf", "sha256:513e6526e0082c59a984448f4104c9bf346c2da9961779ede1fc458e8e8a1f78",
"sha256:9bea19ac2f08672636350f203db89382121c9c2ade85d945953ef3c8cf9d2a68", "sha256:5f587dfd83cb669933186661a351ad6fc7166273bc3e3a1531ec5c783d997aac",
"sha256:a8b8ac7876bc3598e43e2603f772d2353d9931709345ad6c1149009fd1bc81b8", "sha256:62061e87071497951155cbccee487980524d7abea647a1b2a6eb6b9647df9006",
"sha256:b0840b45187699affd4c6588286d429cd79a99d509fe3de0f209594669bb0954", "sha256:641e329e7f2c01531c45c687efcec8aeca2a78a4ff26d49184dce3d53fc35014",
"sha256:b26aaf69713e5674efbde4d728fb7124e429c9466aeaf5f4a7e9e699b12c9fe2", "sha256:65a7e00c00472cd0f59ae09d2fb8a8aaae7f4a0cf54b2b74f3138d9f9ceb9cb2",
"sha256:b63dd43f455ba878e5e9f80ba4f748c0a2156dde6e0e6e690310e24d6e8caf40", "sha256:6ad6ca45e9e92c05295f638e78cd42bfaaf8ee07878c9ed73e93190b26c125f7",
"sha256:be18f4ae5a9e46edae3f329de2191747966a34a3d93046dbdf897319923923bc", "sha256:73aa6e86034dad9f00f4bbf5a666a889d17d79db73bc5af04abd6c20a014d9c8",
"sha256:c312e57847db2526bc92b9bfa78266bfbaabac3fdcd751df4d062cd4c23e46dc", "sha256:7c9762f80a25d8d0e4ab3cb1af5d9dffbddb3ee5d21c43e3474c84bf5ff941f7",
"sha256:c60097190fe9dc2b329a0eb03393e2e0829156a589bd732e70794c0dd804258e", "sha256:85596aa5d9aac1bf39fe39d9fa1051b0f00823982a1de5766e35d495b4a36ca9",
"sha256:c62a2143e1313944bf4a5ab34fd3b4be15367a02e9478b0ce800cb510e3bbb9d", "sha256:86a0ea78fd851b313b2e712266f663e13b6bc78c2fb260b079e8b67d970474b1",
"sha256:cc1109f54a14d940b8512ee9f1c3975c181bbb200306c6d8b87d93376538782f", "sha256:8a620767b8209f3446197c0e29ba895d75a1e272a36af0786ec70fe7834e4307",
"sha256:cd60f507c125ac0ad83f05803063bed27e50fa903b9c2cfee3f8a6867ca600fc", "sha256:922fb9ef2c67c3ab20e22948dcfd783397e4c043a5c5fa5ff5e9df5529074b0a",
"sha256:d513cc3db248e566e07a0da99c230aca3556d9b09ed02f420664e2da97eac301", "sha256:9fad78c13e71546a76c2f8789623eec8e499f8d2d799f4b4547162ce0a4df435",
"sha256:d649dc0bcace6fcdb446ae02b98798a856593b19b637c1b9af8edadf2b150bea", "sha256:a37c6233b28e5bc340054cf6170e7090a4e85069513320275a4dc929144dccf0",
"sha256:d7008a6796095a79544f4da1ee49418901961c97ca9e9d44904205ff7d6aa8cb", "sha256:c3fc325ce4cbf902d05a80daa47b645d07e796a80682c1c5800d6ac5045193e5",
"sha256:da93027835164b8223e8e5af2cf902a4c80ed93cb0909417234f4a9df3bcd9af", "sha256:cda33311cb9fb9323958a69499a667bd728a39a7aa4718d7622597a44c4f1441",
"sha256:e69215621707119c6baf99bda014a45b999d37602cb7043d943c76a59b05bf52", "sha256:db1d4e38c9b15be1521722e946ee24f6db95b189d1447fa9ff18dd16ba89f732",
"sha256:ea9525e0fef2de9208250d6c5aeeee0138921057cd67fcef90fbed49c4d62d37", "sha256:eda55e6e9ea258f5e4add23bcf33dc53b2c319e70806e180aecbff8d90ea24de",
"sha256:fca1669d464f0c9831fd10be2eef6b86f5ebd76c724d1e0706ebdff86bb4adf0" "sha256:f372cdbb240e09ee855735b9d85e7f50730dcfb6296b74b95a3e5dea0615c4c1"
], ],
"index": "pypi", "index": "pypi",
"version": "==5.0.3" "version": "==5.0.4"
}, },
"django": { "django": {
"hashes": [ "hashes": [
"sha256:2f1ba1db8648484dd5c238fb62504777b7ad090c81c5f1fd8d5eb5ec21b5f283", "sha256:642d8eceab321ca743ae71e0f985ff8fdca59f07aab3a9fb362c617d23e33a76",
"sha256:c91c91a7ad6ef67a874a4f76f58ba534f9208412692a840e1d125eb5c279cb0a" "sha256:d4666c2edefa38c5ede0ec1655424c56dc47ceb04b6d8d62a7eac09db89545c1"
], ],
"index": "pypi", "index": "pypi",
"version": "==3.0.3" "version": "==3.0.5"
}, },
"django-debug-toolbar": { "django-debug-toolbar": {
"hashes": [ "hashes": [
@ -966,19 +965,19 @@
"index": "pypi", "index": "pypi",
"version": "==2.2" "version": "==2.2"
}, },
"gitdb2": { "gitdb": {
"hashes": [ "hashes": [
"sha256:0375d983fd887d03c8942e81b1b0abc6c320cfb500cd3fe0d9c0eac87fbf2b52", "sha256:284a6a4554f954d6e737cddcff946404393e030b76a282c6640df8efd6b3da5e",
"sha256:b2b3a67090c17dc61f8407ca485e79ae811225ab5ebcd98ac5ee01448e8987b5" "sha256:598e0096bb3175a0aab3a0b5aedaa18a9a25c6707e0eca0695ba1a0baf1b2150"
], ],
"version": "==3.0.2" "version": "==4.0.2"
}, },
"gitpython": { "gitpython": {
"hashes": [ "hashes": [
"sha256:620b3c729bbc143b498cfea77e302999deedc55faec5b1067086c9ef90e101bc", "sha256:43da89427bdf18bf07f1164c6d415750693b4d50e28fc9b68de706245147b9dd",
"sha256:a43a5d88a5bbc3cf32bb5223e4b4e68fd716db5e9996cad6e561bbfee6e5f4af" "sha256:e426c3b587bd58c482f0b7fe6145ff4ac7ae6c82673fc656f489719abca6f4cb"
], ],
"version": "==3.0.8" "version": "==3.1.0"
}, },
"isort": { "isort": {
"hashes": [ "hashes": [
@ -1022,17 +1021,17 @@
}, },
"pathspec": { "pathspec": {
"hashes": [ "hashes": [
"sha256:163b0632d4e31cef212976cf57b43d9fd6b0bac6e67c26015d611a647d5e7424", "sha256:7d91249d21749788d07a2d0f94147accd8f845507400749ea19c1ec9054a12b0",
"sha256:562aa70af2e0d434367d9790ad37aed893de47f1693e4201fd1d3dca15d19b96" "sha256:da45173eb3a6f2a5a487efba21f050af2b41948be6ab52b6a1e3ff22bb8b7061"
], ],
"version": "==0.7.0" "version": "==0.8.0"
}, },
"pbr": { "pbr": {
"hashes": [ "hashes": [
"sha256:139d2625547dbfa5fb0b81daebb39601c478c21956dc57e2e07b74450a8c506b", "sha256:07f558fece33b05caf857474a366dfcc00562bca13dd8b47b2b3e22d9f9bf55c",
"sha256:61aa52a0f18b71c5cc58232d2cf8f8d09cd67fcad60b742a60124cb8d6951488" "sha256:579170e23f8e0c2f24b0de612f71f648eccb79fb1322c814ae6b3c07b5ba23e8"
], ],
"version": "==5.4.4" "version": "==5.4.5"
}, },
"pycodestyle": { "pycodestyle": {
"hashes": [ "hashes": [
@ -1051,11 +1050,11 @@
}, },
"pylint-django": { "pylint-django": {
"hashes": [ "hashes": [
"sha256:440beb814464928aedd2e21196bb6e47a83b63e2cbe886a701ba0f4a64206bbb", "sha256:3a4cc19dd6301fc2d36c9fb6e15163001a6d12723c1f7f8c2249223c2a8c68f0",
"sha256:d5d113605a64cf0e638b707d4cb42106e626f8851bc30a44d5b22bd698ad8483" "sha256:c9bbcff6b87ee8466fae274fd7aae3d2d3d4c4d1ea20c48cbce673e837e36048"
], ],
"index": "pypi", "index": "pypi",
"version": "==2.0.13" "version": "==2.0.14"
}, },
"pylint-plugin-utils": { "pylint-plugin-utils": {
"hashes": [ "hashes": [
@ -1073,46 +1072,46 @@
}, },
"pyyaml": { "pyyaml": {
"hashes": [ "hashes": [
"sha256:059b2ee3194d718896c0ad077dd8c043e5e909d9180f387ce42012662a4946d6", "sha256:06a0d7ba600ce0b2d2fe2e78453a470b5a6e000a985dd4a4e54e436cc36b0e97",
"sha256:1cf708e2ac57f3aabc87405f04b86354f66799c8e62c28c5fc5f88b5521b2dbf", "sha256:240097ff019d7c70a4922b6869d8a86407758333f02203e0fc6ff79c5dcede76",
"sha256:24521fa2890642614558b492b473bee0ac1f8057a7263156b02e8b14c88ce6f5", "sha256:4f4b913ca1a7319b33cfb1369e91e50354d6f07a135f3b901aca02aa95940bd2",
"sha256:4fee71aa5bc6ed9d5f116327c04273e25ae31a3020386916905767ec4fc5317e", "sha256:69f00dca373f240f842b2931fb2c7e14ddbacd1397d57157a9b005a6a9942648",
"sha256:70024e02197337533eef7b85b068212420f950319cc8c580261963aefc75f811", "sha256:73f099454b799e05e5ab51423c7bcf361c58d3206fa7b0d555426b1f4d9a3eaf",
"sha256:74782fbd4d4f87ff04159e986886931456a1894c61229be9eaf4de6f6e44b99e", "sha256:74809a57b329d6cc0fdccee6318f44b9b8649961fa73144a98735b0aaf029f1f",
"sha256:940532b111b1952befd7db542c370887a8611660d2b9becff75d39355303d82d", "sha256:7739fc0fa8205b3ee8808aea45e968bc90082c10aef6ea95e855e10abf4a37b2",
"sha256:cb1f2f5e426dc9f07a7681419fe39cee823bb74f723f36f70399123f439e9b20", "sha256:95f71d2af0ff4227885f7a6605c37fd53d3a106fcab511b8860ecca9fcf400ee",
"sha256:dbbb2379c19ed6042e8f11f2a2c66d39cceb8aeace421bfc29d085d93eda3689", "sha256:b8eac752c5e14d3eca0e6dd9199cd627518cb5ec06add0de9d32baeee6fe645d",
"sha256:e3a057b7a64f1222b56e47bcff5e4b94c4f61faac04c7c4ecb1985e18caa3994", "sha256:cc8955cfbfc7a115fa81d85284ee61147059a753344bc51098f3ccd69b0d7e0c",
"sha256:e9f45bd5b92c7974e59bcd2dcc8631a6b6cc380a904725fce7bc08872e691615" "sha256:d13155f591e6fcc1ec3b30685d50bf0711574e2c0dfffd7644babf8b5102ca1a"
], ],
"index": "pypi", "index": "pypi",
"version": "==5.3" "version": "==5.3.1"
}, },
"regex": { "regex": {
"hashes": [ "hashes": [
"sha256:07b39bf943d3d2fe63d46281d8504f8df0ff3fe4c57e13d1656737950e53e525", "sha256:08119f707f0ebf2da60d2f24c2f39ca616277bb67ef6c92b72cbf90cbe3a556b",
"sha256:0932941cdfb3afcbc26cc3bcf7c3f3d73d5a9b9c56955d432dbf8bbc147d4c5b", "sha256:0ce9537396d8f556bcfc317c65b6a0705320701e5ce511f05fc04421ba05b8a8",
"sha256:0e182d2f097ea8549a249040922fa2b92ae28be4be4895933e369a525ba36576", "sha256:1cbe0fa0b7f673400eb29e9ef41d4f53638f65f9a2143854de6b1ce2899185c3",
"sha256:10671601ee06cf4dc1bc0b4805309040bb34c9af423c12c379c83d7895622bb5", "sha256:2294f8b70e058a2553cd009df003a20802ef75b3c629506be20687df0908177e",
"sha256:23e2c2c0ff50f44877f64780b815b8fd2e003cda9ce817a7fd00dea5600c84a0", "sha256:23069d9c07e115537f37270d1d5faea3e0bdded8279081c4d4d607a2ad393683",
"sha256:26ff99c980f53b3191d8931b199b29d6787c059f2e029b2b0c694343b1708c35", "sha256:24f4f4062eb16c5bbfff6a22312e8eab92c2c99c51a02e39b4eae54ce8255cd1",
"sha256:27429b8d74ba683484a06b260b7bb00f312e7c757792628ea251afdbf1434003", "sha256:295badf61a51add2d428a46b8580309c520d8b26e769868b922750cf3ce67142",
"sha256:3e77409b678b21a056415da3a56abfd7c3ad03da71f3051bbcdb68cf44d3c34d", "sha256:2a3bf8b48f8e37c3a40bb3f854bf0121c194e69a650b209628d951190b862de3",
"sha256:4e8f02d3d72ca94efc8396f8036c0d3bcc812aefc28ec70f35bb888c74a25161", "sha256:4385f12aa289d79419fede43f979e372f527892ac44a541b5446617e4406c468",
"sha256:4eae742636aec40cf7ab98171ab9400393360b97e8f9da67b1867a9ee0889b26", "sha256:5635cd1ed0a12b4c42cce18a8d2fb53ff13ff537f09de5fd791e97de27b6400e",
"sha256:6a6ae17bf8f2d82d1e8858a47757ce389b880083c4ff2498dba17c56e6c103b9", "sha256:5bfed051dbff32fd8945eccca70f5e22b55e4148d2a8a45141a3b053d6455ae3",
"sha256:6a6ba91b94427cd49cd27764679024b14a96874e0dc638ae6bdd4b1a3ce97be1", "sha256:7e1037073b1b7053ee74c3c6c0ada80f3501ec29d5f46e42669378eae6d4405a",
"sha256:7bcd322935377abcc79bfe5b63c44abd0b29387f267791d566bbb566edfdd146", "sha256:90742c6ff121a9c5b261b9b215cb476eea97df98ea82037ec8ac95d1be7a034f",
"sha256:98b8ed7bb2155e2cbb8b76f627b2fd12cf4b22ab6e14873e8641f266e0fb6d8f", "sha256:a58dd45cb865be0ce1d5ecc4cfc85cd8c6867bea66733623e54bd95131f473b6",
"sha256:bd25bb7980917e4e70ccccd7e3b5740614f1c408a642c245019cff9d7d1b6149", "sha256:c087bff162158536387c53647411db09b6ee3f9603c334c90943e97b1052a156",
"sha256:d0f424328f9822b0323b3b6f2e4b9c90960b24743d220763c7f07071e0778351", "sha256:c162a21e0da33eb3d31a3ac17a51db5e634fc347f650d271f0305d96601dc15b",
"sha256:d58e4606da2a41659c84baeb3cfa2e4c87a74cec89a1e7c56bee4b956f9d7461", "sha256:c9423a150d3a4fc0f3f2aae897a59919acd293f4cb397429b120a5fcd96ea3db",
"sha256:e3cd21cc2840ca67de0bbe4071f79f031c81418deb544ceda93ad75ca1ee9f7b", "sha256:ccccdd84912875e34c5ad2d06e1989d890d43af6c2242c6fcfa51556997af6cd",
"sha256:e6c02171d62ed6972ca8631f6f34fa3281d51db8b326ee397b9c83093a6b7242", "sha256:e91ba11da11cf770f389e47c3f5c30473e6d85e06d7fd9dcba0017d2867aab4a",
"sha256:e7c7661f7276507bce416eaae22040fd91ca471b5b33c13f8ff21137ed6f248c", "sha256:ea4adf02d23b437684cd388d557bf76e3afa72f7fed5bbc013482cc00c816948",
"sha256:ecc6de77df3ef68fee966bb8cb4e067e84d4d1f397d0ef6fce46913663540d77" "sha256:fb95debbd1a824b2c4376932f2216cc186912e389bdb0e27147778cf6acb3f89"
], ],
"version": "==2020.1.8" "version": "==2020.4.4"
}, },
"six": { "six": {
"hashes": [ "hashes": [
@ -1121,19 +1120,19 @@
], ],
"version": "==1.14.0" "version": "==1.14.0"
}, },
"smmap2": { "smmap": {
"hashes": [ "hashes": [
"sha256:0555a7bf4df71d1ef4218e4807bbf9b201f910174e6e08af2e138d4e517b4dde", "sha256:171484fe62793e3626c8b05dd752eb2ca01854b0c55a1efc0dc4210fccb65446",
"sha256:29a9ffa0497e7f2be94ca0ed1ca1aa3cd4cf25a1f6b4f5f87f74b46ed91d609a" "sha256:5fead614cf2de17ee0707a8c6a5f2aa5a2fc6c698c70993ba42f515485ffda78"
], ],
"version": "==2.0.5" "version": "==3.0.1"
}, },
"sqlparse": { "sqlparse": {
"hashes": [ "hashes": [
"sha256:40afe6b8d4b1117e7dff5504d7a8ce07d9a1b15aeeade8a2d10f130a834f8177", "sha256:022fb9c87b524d1f7862b3037e541f68597a730a8843245c349fc93e1643dc4e",
"sha256:7c3dca29c022744e95b547e867cee89f4fce4373f3549ccd8797d8eb52cdb873" "sha256:e162203737712307dfe78860cc56c8da8a852ab2ee33750e33aeadf38d12c548"
], ],
"version": "==0.3.0" "version": "==0.3.1"
}, },
"stevedore": { "stevedore": {
"hashes": [ "hashes": [
@ -1177,11 +1176,11 @@
}, },
"unittest-xml-reporting": { "unittest-xml-reporting": {
"hashes": [ "hashes": [
"sha256:6584562cde8226fc79fa29e38903c669a02799074a563bb0b70fcd3a8e87829c", "sha256:74eaf7739a7957a74f52b8187c5616f61157372189bef0a32ba5c30bbc00e58a",
"sha256:dd8046a64dc62f3d30301523a54992e0be75a945194491e0a3b718130cb429e0" "sha256:e09b8ae70cce9904cdd331f53bf929150962869a5324ab7ff3dd6c8b87e01f7d"
], ],
"index": "pypi", "index": "pypi",
"version": "==3.0.1" "version": "==3.0.2"
}, },
"wrapt": { "wrapt": {
"hashes": [ "hashes": [

View File

@ -1,6 +1,6 @@
apiVersion: v1 apiVersion: v1
appVersion: "0.8.11-beta" appVersion: "0.8.14-beta"
description: A Helm chart for passbook. description: A Helm chart for passbook.
name: passbook name: passbook
version: "0.8.11-beta" version: "0.8.14-beta"
icon: https://git.beryju.org/uploads/-/system/project/avatar/108/logo.png icon: https://git.beryju.org/uploads/-/system/project/avatar/108/logo.png

View File

@ -2,7 +2,7 @@
# This is a YAML-formatted file. # This is a YAML-formatted file.
# Declare variables to be passed into your templates. # Declare variables to be passed into your templates.
image: image:
tag: 0.8.11-beta tag: 0.8.14-beta
nameOverride: "" nameOverride: ""

View File

@ -27,7 +27,7 @@ nav:
- Sentry: integrations/services/sentry/index.md - Sentry: integrations/services/sentry/index.md
- Ansible Tower/AWX: integrations/services/tower-awx/index.md - Ansible Tower/AWX: integrations/services/tower-awx/index.md
repo_name: "BeryJu.org/passbook" repo_name: "BeryJu/passbook"
repo_url: https://github.com/BeryJu/passbook repo_url: https://github.com/BeryJu/passbook
theme: theme:
name: "material" name: "material"

View File

@ -1,2 +1,2 @@
"""passbook""" """passbook"""
__version__ = "0.8.11-beta" __version__ = "0.8.14-beta"

View File

@ -1,66 +1,68 @@
{% extends "administration/base.html" %} {% extends "base/page.html" %}
{% load i18n %} {% load i18n %}
{% load utils %} {% load utils %}
{% block content %} {% block page_content %}
<section class="pf-c-page__main-section pf-m-light"> <main role="main" class="pf-c-page__main" tabindex="-1" id="main-content">
<div class="pf-c-content"> <section class="pf-c-page__main-section pf-m-light">
<h1> <div class="pf-c-content">
<i class="pf-icon pf-icon-catalog"></i> <h1>
{% trans 'Audit Log' %} <i class="pf-icon pf-icon-catalog"></i>
</h1> {% trans 'Audit Log' %}
</div> </h1>
</section>
<section class="pf-c-page__main-section pf-m-no-padding-mobile">
<div class="pf-c-card">
<div class="pf-c-toolbar" id="page-layout-table-simple-toolbar-top">
{% include 'partials/pagination.html' %}
</div> </div>
<table class="pf-c-table pf-m-compact pf-m-grid-xl" role="grid"> </section>
<thead> <section class="pf-c-page__main-section pf-m-no-padding-mobile">
<tr role="row"> <div class="pf-c-card">
<th role="columnheader" scope="col">{% trans 'Action' %}</th> <div class="pf-c-toolbar" id="page-layout-table-simple-toolbar-top">
<th role="columnheader" scope="col">{% trans 'Context' %}</th> {% include 'partials/pagination.html' %}
<th role="columnheader" scope="col">{% trans 'User' %}</th> </div>
<th role="columnheader" scope="col">{% trans 'Creation Date' %}</th> <table class="pf-c-table pf-m-compact pf-m-grid-xl" role="grid">
<th role="columnheader" scope="col">{% trans 'Client IP' %}</th> <thead>
</tr> <tr role="row">
</thead> <th role="columnheader" scope="col">{% trans 'Action' %}</th>
<tbody role="rowgroup"> <th role="columnheader" scope="col">{% trans 'Context' %}</th>
{% for entry in object_list %} <th role="columnheader" scope="col">{% trans 'User' %}</th>
<tr role="row"> <th role="columnheader" scope="col">{% trans 'Creation Date' %}</th>
<th role="columnheader"> <th role="columnheader" scope="col">{% trans 'Client IP' %}</th>
<div> </tr>
<div>{{ entry.action }}</div> </thead>
<small>{{ entry.app|default:'-' }}</small> <tbody role="rowgroup">
</div> {% for entry in object_list %}
</th> <tr role="row">
<td role="cell"> <th role="columnheader">
<code>{{ entry.context }}</code> <div>
</td> <div>{{ entry.action }}</div>
<td role="cell"> <small>{{ entry.app|default:'-' }}</small>
<span> </div>
{{ entry.user }} </th>
</span> <td role="cell">
</td> <code>{{ entry.context }}</code>
<td role="cell"> </td>
<span> <td role="cell">
{{ entry.created }} <span>
</span> {{ entry.user }}
</td> </span>
<td role="cell"> </td>
<span> <td role="cell">
{{ entry.client_ip }} <span>
</span> {{ entry.created }}
</td> </span>
</tr> </td>
{% endfor %} <td role="cell">
</tbody> <span>
</table> {{ entry.client_ip }}
<div class="pf-c-toolbar" id="page-layout-table-simple-toolbar-bottom"> </span>
{% include 'partials/pagination.html' %} </td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="pf-c-toolbar" id="page-layout-table-simple-toolbar-bottom">
{% include 'partials/pagination.html' %}
</div>
</div> </div>
</div> </section>
</section> </main>
{% endblock %} {% endblock %}

View File

@ -1,6 +1,10 @@
{% extends "overview/base.html" %} {% extends "base/page.html" %}
{% load static %} {% load static %}
{% load i18n %}
{% load is_active %}
{% load utils %}
{% block head %} {% block head %}
{{ block.super }} {{ block.super }}
@ -12,3 +16,84 @@
<script src="{% static 'node_modules/codemirror/mode/yaml/yaml.js' %}"></script> <script src="{% static 'node_modules/codemirror/mode/yaml/yaml.js' %}"></script>
<script src="{% static 'node_modules/codemirror/mode/jinja2/jinja2.js' %}"></script> <script src="{% static 'node_modules/codemirror/mode/jinja2/jinja2.js' %}"></script>
{% endblock %} {% endblock %}
{% block page_content %}
<div class="pf-c-page__sidebar">
<div class="pf-c-page__sidebar-body">
<nav class="pf-c-nav" id="page-default-nav-example-primary-nav" aria-label="Global">
<ul class="pf-c-nav__list">
<li class="pf-c-nav__item">
<a href="{% url 'passbook_admin:overview' %}"
class="pf-c-nav__link {% is_active_url 'passbook_admin:overview' %}">
{% trans 'System Status' %}
</a>
</li>
<li class="pf-c-nav__item">
<a href="{% url 'passbook_admin:applications' %}"
class="pf-c-nav__link {% is_active 'passbook_admin:applications' 'passbook_admin:application-create' 'passbook_admin:application-update' 'passbook_admin:application-delete' %}">
{% trans 'Applications' %}
</a>
</li>
<li class="pf-c-nav__item">
<a href="{% url 'passbook_admin:sources' %}"
class="pf-c-nav__link {% is_active 'passbook_admin:sources' 'passbook_admin:source-create' 'passbook_admin:source-update' 'passbook_admin:source-delete' %}">
{% trans 'Sources' %}
</a>
</li>
<li class="pf-c-nav__item">
<a href="{% url 'passbook_admin:providers' %}"
class="pf-c-nav__link {% is_active 'passbook_admin:providers' 'passbook_admin:provider-create' 'passbook_admin:provider-update' 'passbook_admin:provider-delete' %}">
{% trans 'Providers' %}
</a>
</li>
<li class="pf-c-nav__item">
<a href="{% url 'passbook_admin:property-mappings' %}"
class="pf-c-nav__link {% is_active 'passbook_admin:property-mappings' 'passbook_admin:property-mapping-create' 'passbook_admin:property-mapping-update' 'passbook_admin:property-mapping-delete' %}">
{% trans 'Property Mappings' %}
</a>
</li>
<li class="pf-c-nav__item">
<a href="{% url 'passbook_admin:factors' %}"
class="pf-c-nav__link {% is_active 'passbook_admin:factors' 'passbook_admin:factor-create' 'passbook_admin:factor-update' 'passbook_admin:factor-delete' %}">
{% trans 'Factors' %}
</a>
</li>
<li class="pf-c-nav__item">
<a href="{% url 'passbook_admin:policies' %}"
class="pf-c-nav__link {% is_active 'passbook_admin:policies' 'passbook_admin:policy-create' 'passbook_admin:policy-update' 'passbook_admin:policy-delete' 'passbook_admin:policy-test' %}">
{% trans 'Policies' %}
</a>
</li>
<li class="pf-c-nav__item">
<a href="{% url 'passbook_admin:certificate_key_pair' %}"
class="pf-c-nav__link {% is_active 'passbook_admin:certificate_key_pair' 'passbook_admin:certificatekeypair-create' 'passbook_admin:certificatekeypair-update' 'passbook_admin:certificatekeypair-delete' %}">
{% trans 'Certificates' %}
</a>
</li>
<li class="pf-c-nav__item">
<a href="{% url 'passbook_admin:invitations' %}"
class="pf-c-nav__link {% is_active 'passbook_admin:invitations' 'passbook_admin:invitation-create' 'passbook_admin:invitation-update' 'passbook_admin:invitation-delete' 'passbook_admin:invitation-test' %}">
{% trans 'Invitations' %}
</a>
</li>
<li class="pf-c-nav__item">
<a href="{% url 'passbook_admin:users' %}"
class="pf-c-nav__link {% is_active 'passbook_admin:users' 'passbook_admin:user-update' 'passbook_admin:user-delete' %}">
{% trans 'Users' %}
</a>
</li>
<li class="pf-c-nav__item">
<a href="{% url 'passbook_admin:groups' %}"
class="pf-c-nav__link {% is_active 'passbook_admin:groups' 'passbook_admin:group-update' 'passbook_admin:group-delete' %}">
{% trans 'Groups' %}
</a>
</li>
</ul>
</nav>
</div>
</div>
<main role="main" class="pf-c-page__main" tabindex="-1" id="main-content">
{% block content %}
{% endblock %}
</main>
{% endblock %}

View File

@ -0,0 +1,69 @@
{% extends "administration/base.html" %}
{% load i18n %}
{% load utils %}
{% block content %}
<section class="pf-c-page__main-section pf-m-light">
<div class="pf-c-content">
<h1>
<i class="pf-icon pf-icon-key"></i>
{% trans 'Certificate-Key Pairs' %}
</h1>
<p>{% trans "Import certificates of external providers or create certificates to sign requests with." %}</p>
</div>
</section>
<section class="pf-c-page__main-section pf-m-no-padding-mobile">
<div class="pf-c-card">
<div class="pf-c-toolbar" id="page-layout-table-simple-toolbar-top">
<div class="pf-c-toolbar__action-group">
<a href="{% url 'passbook_admin:certificatekeypair-create' %}?back={{ request.get_full_path }}" class="pf-c-button pf-m-primary" type="button">{% trans 'Create' %}</a>
</div>
{% include 'partials/pagination.html' %}
</div>
<table class="pf-c-table pf-m-compact pf-m-grid-xl" role="grid">
<thead>
<tr role="row">
<th role="columnheader" scope="col">{% trans 'Name' %}</th>
<th role="columnheader" scope="col">{% trans 'Private Key available' %}</th>
<th role="columnheader" scope="col">{% trans 'Fingerprint' %}</th>
<th role="columnheader" scope="col">{% trans 'Provider Type' %}</th>
<th role="cell"></th>
</tr>
</thead>
<tbody role="rowgroup">
{% for kp in object_list %}
<tr role="row">
<th role="columnheader">
<div>
<div>{{ kp.name }}</div>
</div>
</th>
<td role="cell">
<span>
{% if kp.key_data is not None %}
{% trans 'Yes' %}
{% else %}
{% trans 'No' %}
{% endif %}
</span>
</td>
<td role="cell">
<span>
{{ kp.fingerprint }}
</span>
</td>
<td>
<a class="pf-c-button pf-m-secondary" href="{% url 'passbook_admin:certificatekeypair-update' pk=kp.pk %}?back={{ request.get_full_path }}">{% trans 'Edit' %}</a>
<a class="pf-c-button pf-m-danger" href="{% url 'passbook_admin:certificatekeypair-delete' pk=kp.pk %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="pf-c-toolbar" id="page-layout-table-simple-toolbar-bottom">
{% include 'partials/pagination.html' %}
</div>
</div>
</section>
{% endblock %}

View File

@ -4,6 +4,7 @@ from django.urls import path
from passbook.admin.views import ( from passbook.admin.views import (
applications, applications,
audit, audit,
certificate_key_pair,
debug, debug,
factors, factors,
groups, groups,
@ -148,6 +149,27 @@ urlpatterns = [
path( path(
"group/<uuid:pk>/delete/", groups.GroupDeleteView.as_view(), name="group-delete" "group/<uuid:pk>/delete/", groups.GroupDeleteView.as_view(), name="group-delete"
), ),
# Certificate-Key Pairs
path(
"crypto/certificates/",
certificate_key_pair.CertificateKeyPairListView.as_view(),
name="certificate_key_pair",
),
path(
"crypto/certificates/create/",
certificate_key_pair.CertificateKeyPairCreateView.as_view(),
name="certificatekeypair-create",
),
path(
"crypto/certificates/<uuid:pk>/update/",
certificate_key_pair.CertificateKeyPairUpdateView.as_view(),
name="certificatekeypair-update",
),
path(
"crypto/certificates/<uuid:pk>/delete/",
certificate_key_pair.CertificateKeyPairDeleteView.as_view(),
name="certificatekeypair-delete",
),
# Audit Log # Audit Log
path("audit/", audit.EventListView.as_view(), name="audit-log"), path("audit/", audit.EventListView.as_view(), name="audit-log"),
# Groups # Groups

View File

@ -12,4 +12,4 @@ class EventListView(PermissionListMixin, ListView):
template_name = "administration/audit/list.html" template_name = "administration/audit/list.html"
permission_required = "passbook_audit.view_event" permission_required = "passbook_audit.view_event"
ordering = "-created" ordering = "-created"
paginate_by = 10 paginate_by = 20

View File

@ -0,0 +1,77 @@
"""passbook CertificateKeyPair administration"""
from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.mixins import (
PermissionRequiredMixin as DjangoPermissionRequiredMixin,
)
from django.contrib.messages.views import SuccessMessageMixin
from django.urls import reverse_lazy
from django.utils.translation import ugettext as _
from django.views.generic import DeleteView, ListView, UpdateView
from guardian.mixins import PermissionListMixin, PermissionRequiredMixin
from passbook.crypto.forms import CertificateKeyPairForm
from passbook.crypto.models import CertificateKeyPair
from passbook.lib.views import CreateAssignPermView
class CertificateKeyPairListView(LoginRequiredMixin, PermissionListMixin, ListView):
"""Show list of all keypairs"""
model = CertificateKeyPair
permission_required = "passbook_crypto.view_certificatekeypair"
ordering = "name"
paginate_by = 40
template_name = "administration/certificatekeypair/list.html"
class CertificateKeyPairCreateView(
SuccessMessageMixin,
LoginRequiredMixin,
DjangoPermissionRequiredMixin,
CreateAssignPermView,
):
"""Create new CertificateKeyPair"""
model = CertificateKeyPair
form_class = CertificateKeyPairForm
permission_required = "passbook_crypto.add_certificatekeypair"
template_name = "generic/create.html"
success_url = reverse_lazy("passbook_admin:certificate_key_pair")
success_message = _("Successfully created CertificateKeyPair")
def get_context_data(self, **kwargs):
kwargs["type"] = "Certificate-Key Pair"
return super().get_context_data(**kwargs)
class CertificateKeyPairUpdateView(
SuccessMessageMixin, LoginRequiredMixin, PermissionRequiredMixin, UpdateView
):
"""Update certificatekeypair"""
model = CertificateKeyPair
form_class = CertificateKeyPairForm
permission_required = "passbook_crypto.change_certificatekeypair"
template_name = "generic/update.html"
success_url = reverse_lazy("passbook_admin:certificate_key_pair")
success_message = _("Successfully updated Certificate-Key Pair")
class CertificateKeyPairDeleteView(
SuccessMessageMixin, LoginRequiredMixin, PermissionRequiredMixin, DeleteView
):
"""Delete certificatekeypair"""
model = CertificateKeyPair
permission_required = "passbook_crypto.delete_certificatekeypair"
template_name = "generic/delete.html"
success_url = reverse_lazy("passbook_admin:certificate_key_pair")
success_message = _("Successfully deleted Certificate-Key Pair")
def delete(self, request, *args, **kwargs):
messages.success(self.request, self.success_message)
return super().delete(request, *args, **kwargs)

View File

@ -23,6 +23,8 @@ class InvitationListView(LoginRequiredMixin, PermissionListMixin, ListView):
model = Invitation model = Invitation
permission_required = "passbook_core.view_invitation" permission_required = "passbook_core.view_invitation"
template_name = "administration/invitation/list.html" template_name = "administration/invitation/list.html"
paginate_by = 10
ordering = "-expires"
class InvitationCreateView( class InvitationCreateView(

View File

@ -24,6 +24,7 @@ class PolicyListView(LoginRequiredMixin, PermissionListMixin, ListView):
model = Policy model = Policy
permission_required = "passbook_core.view_policy" permission_required = "passbook_core.view_policy"
paginate_by = 10
ordering = "order" ordering = "order"
template_name = "administration/policy/list.html" template_name = "administration/policy/list.html"

View File

@ -7,7 +7,7 @@ from rest_framework import routers
from structlog import get_logger from structlog import get_logger
from passbook.api.permissions import CustomObjectPermissions from passbook.api.permissions import CustomObjectPermissions
from passbook.audit.api.events import EventViewSet from passbook.audit.api import EventViewSet
from passbook.core.api.applications import ApplicationViewSet from passbook.core.api.applications import ApplicationViewSet
from passbook.core.api.factors import FactorViewSet from passbook.core.api.factors import FactorViewSet
from passbook.core.api.groups import GroupViewSet from passbook.core.api.groups import GroupViewSet

View File

@ -18,7 +18,7 @@ class EventSerializer(ModelSerializer):
"date", "date",
"app", "app",
"context", "context",
"request_ip", "client_ip",
"created", "created",
] ]

View File

@ -0,0 +1,27 @@
{% extends 'login/base.html' %}
{% load static %}
{% load i18n %}
{% load utils %}
{% block card_title %}
{{ title }} <span>(403)</span>
{% endblock %}
{% block card %}
<form>
<h3>{{ main }}</h3>
{% if no_referer %}
<p>{{ no_referer1 }}</p>
<p>{{ no_referer2 }}</p>
<p>{{ no_referer3 }}</p>
{% endif %}
{% if no_cookie %}
<p>{{ no_cookie1 }}</p>
<p>{{ no_cookie2 }}</p>
{% endif %}
{% if 'back' in request.GET %}
<a href="{% back %}" class="btn btn-primary btn-block btn-lg">{% trans 'Back' %}</a>
{% endif %}
</form>
{% endblock %}

View File

@ -0,0 +1,58 @@
{% extends "base/skeleton.html" %}
{% load static %}
{% load i18n %}
{% load is_active %}
{% load utils %}
{% block body %}
{% include 'partials/messages.html' %}
<div class="pf-c-page" id="page-default-nav-example">
<a class="pf-c-skip-to-content pf-c-button pf-m-primary" href="#main-content">{% trans 'Skip to content' %}</a>
<header role="banner" class="pf-c-page__header ws-page-header">
<div class="pf-c-page__header-brand">
<div class="pf-c-page__header-brand-toggle">
<button class="pf-c-button pf-m-plain" type="button" id="page-default-nav-example-nav-toggle"
aria-label="Global navigation" aria-expanded="true"
aria-controls="page-default-nav-example-primary-nav">
<i class="fas fa-bars" aria-hidden="true"></i>
</button>
</div>
<a class="pf-c-page__header-brand-link">
<img class="pf-c-brand" src="{% static 'passbook/logo.png' %}" alt="" />
<img class="pf-c-brand" src="{% static 'passbook/brand.svg' %}" alt="passbook" />
</a>
</div>
<div class="pf-c-page__header-nav">
<nav class="pf-c-nav" aria-label="Nav">
<ul class="pf-c-nav__horizontal-list ws-top-nav">
<li class="pf-c-nav__item"><a class="pf-c-nav__link {% is_active_url 'passbook_core:overview' %}"
href="{% url 'passbook_core:overview' %}">{% trans 'Access' %}</a></li>
{% if user.is_superuser %}
<li class="pf-c-nav__item"><a class="pf-c-nav__link {% is_active_url 'passbook_admin:overview' %}"
href="{% url 'passbook_admin:overview' %}">{% trans 'Administrate' %}</a></li>
<li class="pf-c-nav__item"><a class="pf-c-nav__link {% is_active_url 'passbook_admin:audit-log' %}"
href="{% url 'passbook_admin:audit-log' %}">{% trans 'Monitor' %}</a></li>
{% endif %}
</ul>
</nav>
</div>
<div class="pf-c-page__header-tools">
<div class="pf-c-page__header-tools-group pf-m-icons">
<a href="{% url 'passbook_core:auth-logout' %}" class="pf-c-button pf-m-plain" type="button">
<i class="fas fa-sign-out-alt" aria-hidden="true"></i>
</a>
</div>
<div class="pf-c-page__header-tools-group">
<a href="{% url 'passbook_core:user-settings' %}" class="pf-c-button">
{{ user.username }}
</a>
</div>
<img class="pf-c-avatar" src="{% gravatar user.email %}" alt="">
</div>
</header>
{% block page_content %}
{% endblock %}
</div>
{% endblock %}

View File

@ -8,7 +8,7 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>{% block title %}{% title %}{% endblock %}</title> <title>{% block title %}{% trans title|default:"passbook" %}{% endblock %}</title>
<link rel="icon" type="image/png" href="{% static 'passbook/logo.png' %}"> <link rel="icon" type="image/png" href="{% static 'passbook/logo.png' %}">
<link rel="shortcut icon" type="image/png" href="{% static 'passbook/logo.png' %}"> <link rel="shortcut icon" type="image/png" href="{% static 'passbook/logo.png' %}">
<link rel="stylesheet" type="text/css" href="{% static 'node_modules/@patternfly/patternfly/patternfly.css' %}"> <link rel="stylesheet" type="text/css" href="{% static 'node_modules/@patternfly/patternfly/patternfly.css' %}">

View File

@ -8,7 +8,6 @@
{% endblock %} {% endblock %}
{% block content %} {% block content %}
{% config 'passbook.branding' as branding %}
<!-- HERO --> <!-- HERO -->
<tr> <tr>
<td bgcolor="#7c72dc" align="center" style="padding: 0px 10px 0px 10px;"> <td bgcolor="#7c72dc" align="center" style="padding: 0px 10px 0px 10px;">

View File

@ -5,7 +5,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<title>{% config passbook.branding %}</title> <title>passbook</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" />
@ -118,7 +118,7 @@
<!-- ADDRESS --> <!-- ADDRESS -->
<tr> <tr>
<td bgcolor="#1b2a32" align="left" style="padding: 0px 30px 30px 30px; color: #E9ECEF; font-family: 'Metropolis', Helvetica, Arial, sans-serif; font-size: 14px; font-weight: 400; line-height: 18px;"> <td bgcolor="#1b2a32" align="left" style="padding: 0px 30px 30px 30px; color: #E9ECEF; font-family: 'Metropolis', Helvetica, Arial, sans-serif; font-size: 14px; font-weight: 400; line-height: 18px;">
<p style="margin: 0;"><a href="{% config 'passbook.branding' %}">{% config 'passbook.branding' %}</a></p> <p style="margin: 0;"><a href="passbook">passbook</a></p>
</td> </td>
</tr> </tr>
</table> </table>

View File

@ -23,7 +23,7 @@
<header class="pf-c-login__header"> <header class="pf-c-login__header">
<img class="pf-c-brand" src="{% static 'passbook/logo.svg' %}" style="height: 60px;" <img class="pf-c-brand" src="{% static 'passbook/logo.svg' %}" style="height: 60px;"
alt="passbook icon" /> alt="passbook icon" />
<img class="pf-c-brand" src="{% static 'passbook/brand.svg' %}" style="height: 80px;" <img class="pf-c-brand" src="{% static 'passbook/brand.svg' %}" style="height: 60px;"
alt="passbook branding" /> alt="passbook branding" />
</header> </header>
<main class="pf-c-login__main"> <main class="pf-c-login__main">

View File

@ -5,7 +5,7 @@
{% load utils %} {% load utils %}
{% block title %} {% block title %}
{% title title %} {% trans title %}
{% endblock %} {% endblock %}
{% block head %} {% block head %}

View File

@ -1,4 +1,4 @@
{% extends "base/skeleton.html" %} {% extends "base/page.html" %}
{% load static %} {% load static %}
{% load i18n %} {% load i18n %}
@ -6,120 +6,9 @@
{% load is_active %} {% load is_active %}
{% load utils %} {% load utils %}
{% block body %} {% block page_content %}
{% include 'partials/messages.html' %} <main role="main" class="pf-c-page__main" tabindex="-1" id="main-content">
<div class="pf-c-page" id="page-default-nav-example"> {% block content %}
<a class="pf-c-skip-to-content pf-c-button pf-m-primary" href="#main-content">{% trans 'Skip to content' %}</a> {% endblock %}
<header role="banner" class="pf-c-page__header"> </main>
<div class="pf-c-page__header-brand">
<div class="pf-c-page__header-brand-toggle">
<button class="pf-c-button pf-m-plain" type="button" id="page-default-nav-example-nav-toggle"
aria-label="Global navigation" aria-expanded="true"
aria-controls="page-default-nav-example-primary-nav">
<i class="fas fa-bars" aria-hidden="true"></i>
</button>
</div>
<a class="pf-c-page__header-brand-link">
<img class="pf-c-brand" src="{% static 'passbook/logo.png' %}" alt="" />
<img class="pf-c-brand" src="{% static 'passbook/brand.svg' %}" alt="passbook" />
</a>
</div>
<div class="pf-c-page__header-tools">
<div class="pf-c-page__header-tools-group pf-m-icons">
<a href="{% url 'passbook_core:auth-logout' %}" class="pf-c-button pf-m-plain" type="button">
<i class="fas fa-sign-out-alt" aria-hidden="true"></i>
</a>
</div>
<div class="pf-c-page__header-tools-group">
<a href="{% url 'passbook_core:user-settings' %}" class="pf-c-button">
{{ user.username }}
</a>
</div>
<img class="pf-c-avatar" src="{% gravatar user.email %}" alt="">
</div>
</header>
<div class="pf-c-page__sidebar pf-m-dark">
<div class="pf-c-page__sidebar-body">
<nav class="pf-c-nav pf-m-dark" id="page-default-nav-example-primary-nav" aria-label="Global">
<ul class="pf-c-nav__list">
<li class="pf-c-nav__item">
<a href="{% url 'passbook_core:overview' %}" class="pf-c-nav__link {% is_active_url 'passbook_core:overview' %}">
{% trans 'Overview' %}
</a>
</li>
{% if user.is_superuser %}
<li class="pf-c-nav__item">
<a href="{% url 'passbook_admin:overview' %}" class="pf-c-nav__link {% is_active_url 'passbook_admin:overview' %}">
{% trans 'System Status' %}
</a>
</li>
<li class="pf-c-nav__item">
<a href="{% url 'passbook_admin:applications' %}" class="pf-c-nav__link {% is_active 'passbook_admin:applications' 'passbook_admin:application-create' 'passbook_admin:application-update' 'passbook_admin:application-delete' %}">
{% trans 'Applications' %}
</a>
</li>
<li class="pf-c-nav__item">
<a href="{% url 'passbook_admin:sources' %}" class="pf-c-nav__link {% is_active 'passbook_admin:sources' 'passbook_admin:source-create' 'passbook_admin:source-update' 'passbook_admin:source-delete' %}">
{% trans 'Sources' %}
</a>
</li>
<li class="pf-c-nav__item">
<a href="{% url 'passbook_admin:providers' %}" class="pf-c-nav__link {% is_active 'passbook_admin:providers' 'passbook_admin:provider-create' 'passbook_admin:provider-update' 'passbook_admin:provider-delete' %}">
{% trans 'Providers' %}
</a>
</li>
<li class="pf-c-nav__item">
<a href="{% url 'passbook_admin:property-mappings' %}" class="pf-c-nav__link {% is_active 'passbook_admin:property-mappings' 'passbook_admin:property-mapping-create' 'passbook_admin:property-mapping-update' 'passbook_admin:property-mapping-delete' %}">
{% trans 'Property Mappings' %}
</a>
</li>
<li class="pf-c-nav__item">
<a href="{% url 'passbook_admin:factors' %}" class="pf-c-nav__link {% is_active 'passbook_admin:factors' 'passbook_admin:factor-create' 'passbook_admin:factor-update' 'passbook_admin:factor-delete' %}">
{% trans 'Factors' %}
</a>
</li>
<li class="pf-c-nav__item">
<a href="{% url 'passbook_admin:policies' %}" class="pf-c-nav__link {% is_active 'passbook_admin:policies' 'passbook_admin:policy-create' 'passbook_admin:policy-update' 'passbook_admin:policy-delete' 'passbook_admin:policy-test' %}">
{% trans 'Policies' %}
</a>
</li>
<li class="pf-c-nav__item">
<a href="{% url 'passbook_admin:invitations' %}" class="pf-c-nav__link {% is_active 'passbook_admin:invitations' 'passbook_admin:invitation-create' 'passbook_admin:invitation-update' 'passbook_admin:invitation-delete' 'passbook_admin:invitation-test' %}">
{% trans 'Invitations' %}
</a>
</li>
<li class="pf-c-nav__item">
<a href="{% url 'passbook_admin:users' %}" class="pf-c-nav__link {% is_active 'passbook_admin:users' 'passbook_admin:user-update' 'passbook_admin:user-delete' %}">
{% trans 'Users' %}
</a>
</li>
<li class="pf-c-nav__item">
<a href="{% url 'passbook_admin:groups' %}" class="pf-c-nav__link {% is_active 'passbook_admin:groups' 'passbook_admin:group-update' 'passbook_admin:group-delete' %}">
{% trans 'Groups' %}
</a>
</li>
<li class="pf-c-nav__item">
<a href="{% url 'passbook_admin:audit-log' %}" class="pf-c-nav__link {% is_active 'passbook_admin:audit-log' %}">
{% trans 'Audit Log' %}
</a>
</li>
{% endif %}
</ul>
</nav>
</div>
</div>
<main role="main" class="pf-c-page__main" tabindex="-1" id="main-content">
{% block content %}
<section class="pf-c-page__main-section pf-m-light">
<div class="pf-c-content">
<h1>Main title</h1>
<p>This is a demo of the Page component.</p>
</div>
</section>
<section class="pf-c-page__main-section">
</section>
{% endblock %}
</main>
</div>
{% endblock %} {% endblock %}

View File

@ -1,67 +1,69 @@
{% extends "overview/base.html" %} {% extends "base/page.html" %}
{% load i18n %} {% load i18n %}
{% load is_active %} {% load is_active %}
{% load static %} {% load static %}
{% load passbook_user_settings %} {% load passbook_user_settings %}
{% block content %} {% block page_content %}
<section class="pf-c-page__main-section"> <div class="pf-c-page__sidebar">
<div class="pf-l-split pf-m-gutter"> <div class="pf-c-page__sidebar-body">
<div class="pf-l-split__item"> <nav class="pf-c-nav" id="page-default-nav-example-primary-nav" aria-label="Global">
<div class="pf-c-card"> <section class="pf-c-nav__section">
<div class="pf-c-card__body"> <h2 class="pf-c-nav__section-title">{% trans 'General Settings' %}</h2>
<nav class="pf-c-nav" aria-label="Global"> <ul class="pf-c-nav__list">
<section class="pf-c-nav__section"> <li class="pf-c-nav__item">
<h2 class="pf-c-nav__section-title">{% trans 'General Settings' %}</h2> <a href="{% url 'passbook_core:user-settings' %}"
<ul class="pf-c-nav__list"> class="pf-c-nav__link {% is_active 'passbook_core:user-settings' %}">{% trans 'User Details' %}</a>
<li class="pf-c-nav__item"> </li>
<a href="{% url 'passbook_core:user-settings' %}" class="pf-c-nav__link {% is_active 'passbook_core:user-settings' %}">{% trans 'User Details' %}</a> </ul>
</li> </section>
</ul> {% user_factors as user_factors_loc %}
</section> {% if user_factors_loc %}
{% user_factors as user_factors_loc %} <section class="pf-c-nav__section">
{% if user_factors_loc %} <h2 class="pf-c-nav__section-title">{% trans 'Factors' %}</h2>
<section class="pf-c-nav__section"> <ul class="pf-c-nav__list">
<h2 class="pf-c-nav__section-title">{% trans 'Factors' %}</h2> {% for factor in user_factors_loc %}
<ul class="pf-c-nav__list"> <li class="pf-c-nav__item">
{% for factor in user_factors_loc %} <a href="{% url factor.view_name %}" class="pf-c-nav__link {% is_active factor.view_name %}">
<li class="pf-c-nav__item"> <i class="{{ factor.icon }}"></i>
<a href="{% url factor.view_name %}" class="pf-c-nav__link {% is_active factor.view_name %}"> {{ factor.name }}
<i class="{{ factor.icon }}"></i> </a>
{{ factor.name }} </li>
</a> {% endfor %}
</li> </ul>
{% endfor %} </section>
</ul> {% endif %}
</section> {% user_sources as user_sources_loc %}
{% endif %} {% if user_sources_loc %}
{% user_sources as user_sources_loc %} <section class="pf-c-nav__section">
{% if user_sources_loc %} <h2 class="pf-c-nav__section-title">{% trans 'Sources' %}</h2>
<section class="pf-c-nav__section"> <ul class="pf-c-nav__list">
<h2 class="pf-c-nav__section-title">{% trans 'Sources' %}</h2> {% for source in user_sources_loc %}
<ul class="pf-c-nav__list"> <li class="pf-c-nav__item">
{% for source in user_sources_loc %} <a href="{{ source.view_name }}"
<li class="pf-c-nav__item"> class="pf-c-nav__link {% if user_settings.view_name == request.get_full_path %} pf-m-current {% endif %}">
<a href="{{ source.view_name }}" class="pf-c-nav__link {% if user_settings.view_name == request.get_full_path %} pf-m-current {% endif %}"> <i class="{{ source.icon }}"></i>
<i class="{{ source.icon }}"></i> {{ source.name }}
{{ source.name }} </a>
</a> </li>
</li> {% endfor %}
{% endfor %} </ul>
</ul> </section>
</section> {% endif %}
{% endif %} </nav>
</nav> </div>
</div>
<main role="main" class="pf-c-page__main" tabindex="-1" id="main-content">
<section class="pf-c-page__main-section">
<div class="pf-l-split pf-m-gutter">
<div class="pf-l-split__item">
<div class="pf-c-card">
{% block page %}
{% endblock %}
</div> </div>
</div> </div>
</div> </div>
<div class="pf-l-split__item"> </section>
<div class="pf-c-card"> </main>
{% block page %}
{% endblock %}
</div>
</div>
</div>
</section>
{% endblock %} {% endblock %}

5
passbook/crypto/admin.py Normal file
View File

@ -0,0 +1,5 @@
"""passbook crypto model admin"""
from passbook.lib.admin import admin_autoregister
admin_autoregister("passbook_crypto")

10
passbook/crypto/apps.py Normal file
View File

@ -0,0 +1,10 @@
"""passbook crypto app config"""
from django.apps import AppConfig
class PassbookCryptoConfig(AppConfig):
"""passbook crypto app config"""
name = "passbook.crypto"
label = "passbook_crypto"
verbose_name = "passbook Crypto"

View File

@ -36,8 +36,7 @@ class CertificateBuilder:
x509.Name( x509.Name(
[ [
x509.NameAttribute( x509.NameAttribute(
NameOID.COMMON_NAME, NameOID.COMMON_NAME, u"passbook Self-signed Certificate",
u"passbook Self-signed SAML Certificate",
), ),
x509.NameAttribute(NameOID.ORGANIZATION_NAME, u"passbook"), x509.NameAttribute(NameOID.ORGANIZATION_NAME, u"passbook"),
x509.NameAttribute( x509.NameAttribute(
@ -50,8 +49,7 @@ class CertificateBuilder:
x509.Name( x509.Name(
[ [
x509.NameAttribute( x509.NameAttribute(
NameOID.COMMON_NAME, NameOID.COMMON_NAME, u"passbook Self-signed Certificate",
u"passbook Self-signed SAML Certificate",
), ),
] ]
) )

27
passbook/crypto/forms.py Normal file
View File

@ -0,0 +1,27 @@
"""passbook Crypto forms"""
from django import forms
from django.utils.translation import gettext_lazy as _
from passbook.crypto.models import CertificateKeyPair
class CertificateKeyPairForm(forms.ModelForm):
"""CertificateKeyPair Form"""
class Meta:
model = CertificateKeyPair
fields = [
"name",
"certificate_data",
"key_data",
]
widgets = {
"name": forms.TextInput(),
"certificate_data": forms.Textarea(attrs={"class": "monospaced"}),
"key_data": forms.Textarea(attrs={"class": "monospaced"}),
}
labels = {
"certificate_data": _("Certificate"),
"key_data": _("Private Key"),
}

View File

@ -0,0 +1,67 @@
# Generated by Django 3.0.3 on 2020-03-03 21:45
import uuid
from django.db import migrations, models
def create_self_signed(apps, schema_editor):
CertificateKeyPair = apps.get_model("passbook_crypto", "CertificateKeyPair")
db_alias = schema_editor.connection.alias
from passbook.crypto.builder import CertificateBuilder
builder = CertificateBuilder()
builder.build()
CertificateKeyPair.objects.using(db_alias).create(
name="passbook Self-signed Certificate",
certificate_data=builder.certificate,
key_data=builder.private_key,
)
class Migration(migrations.Migration):
initial = True
dependencies = []
operations = [
migrations.CreateModel(
name="CertificateKeyPair",
fields=[
("created", models.DateTimeField(auto_now_add=True)),
("last_updated", models.DateTimeField(auto_now=True)),
(
"uuid",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
),
),
("name", models.TextField()),
("certificate_data", models.TextField()),
("key_data", models.TextField(blank=True, default="")),
],
options={
"verbose_name": "Certificate-Key Pair",
"verbose_name_plural": "Certificate-Key Pairs",
},
),
migrations.RunPython(create_self_signed),
migrations.AlterField(
model_name="certificatekeypair",
name="certificate_data",
field=models.TextField(help_text="PEM-encoded Certificate data"),
),
migrations.AlterField(
model_name="certificatekeypair",
name="key_data",
field=models.TextField(
blank=True,
default="",
help_text="Optional Private Key. If this is set, you can use this keypair for encryption.",
),
),
]

View File

64
passbook/crypto/models.py Normal file
View File

@ -0,0 +1,64 @@
"""passbook crypto models"""
from binascii import hexlify
from typing import Optional
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey
from cryptography.hazmat.primitives.serialization import load_pem_private_key
from cryptography.x509 import Certificate, load_pem_x509_certificate
from django.db import models
from django.utils.translation import gettext_lazy as _
from passbook.lib.models import CreatedUpdatedModel, UUIDModel
class CertificateKeyPair(UUIDModel, CreatedUpdatedModel):
"""CertificateKeyPair that can be used for signing or encrypting if `key_data`
is set, otherwise it can be used to verify remote data."""
name = models.TextField()
certificate_data = models.TextField(help_text=_("PEM-encoded Certificate data"))
key_data = models.TextField(
help_text=_(
"Optional Private Key. If this is set, you can use this keypair for encryption."
),
blank=True,
default="",
)
_cert: Optional[Certificate] = None
_key: Optional[RSAPrivateKey] = None
@property
def certificate(self) -> Certificate:
"""Get python cryptography Certificate instance"""
if not self._cert:
self._cert = load_pem_x509_certificate(
self.certificate_data.encode("utf-8"), default_backend()
)
return self._cert
@property
def private_key(self) -> Optional[RSAPrivateKey]:
"""Get python cryptography PrivateKey instance"""
if not self._key:
self._key = load_pem_private_key(
str.encode("\n".join([x.strip() for x in self.key_data.split("\n")])),
password=None,
backend=default_backend(),
)
return self._key
@property
def fingerprint(self) -> str:
"""Get SHA256 Fingerprint of certificate_data"""
return hexlify(self.certificate.fingerprint(hashes.SHA256())).decode("utf-8")
def __str__(self) -> str:
return f"Certificate-Key Pair {self.name} {self.fingerprint}"
class Meta:
verbose_name = _("Certificate-Key Pair")
verbose_name_plural = _("Certificate-Key Pairs")

View File

@ -2,7 +2,7 @@
from captcha.fields import ReCaptchaField from captcha.fields import ReCaptchaField
from django import forms from django import forms
from django.contrib.admin.widgets import FilteredSelectMultiple from django.contrib.admin.widgets import FilteredSelectMultiple
from django.utils.translation import gettext as _ from django.utils.translation import gettext_lazy as _
from passbook.factors.captcha.models import CaptchaFactor from passbook.factors.captcha.models import CaptchaFactor
from passbook.factors.forms import GENERAL_FIELDS from passbook.factors.forms import GENERAL_FIELDS
@ -28,3 +28,8 @@ class CaptchaFactorForm(forms.ModelForm):
"public_key": forms.TextInput(), "public_key": forms.TextInput(),
"private_key": forms.TextInput(), "private_key": forms.TextInput(),
} }
help_texts = {
"policies": _(
"Policies which determine if this factor applies to the current user."
)
}

View File

@ -1,7 +1,7 @@
"""passbook administration forms""" """passbook administration forms"""
from django import forms from django import forms
from django.contrib.admin.widgets import FilteredSelectMultiple from django.contrib.admin.widgets import FilteredSelectMultiple
from django.utils.translation import gettext as _ from django.utils.translation import gettext_lazy as _
from passbook.factors.email.models import EmailFactor from passbook.factors.email.models import EmailFactor
from passbook.factors.forms import GENERAL_FIELDS from passbook.factors.forms import GENERAL_FIELDS
@ -41,3 +41,8 @@ class EmailFactorForm(forms.ModelForm):
"ssl_keyfile": _("SSL Keyfile (optional)"), "ssl_keyfile": _("SSL Keyfile (optional)"),
"ssl_certfile": _("SSL Certfile (optional)"), "ssl_certfile": _("SSL Certfile (optional)"),
} }
help_texts = {
"policies": _(
"Policies which determine if this factor applies to the current user."
)
}

View File

@ -4,7 +4,7 @@ from django import forms
from django.contrib.admin.widgets import FilteredSelectMultiple from django.contrib.admin.widgets import FilteredSelectMultiple
from django.core.validators import RegexValidator from django.core.validators import RegexValidator
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django_otp.models import Device from django_otp.models import Device
from passbook.factors.forms import GENERAL_FIELDS from passbook.factors.forms import GENERAL_FIELDS
@ -80,3 +80,8 @@ class OTPFactorForm(forms.ModelForm):
"order": forms.NumberInput(), "order": forms.NumberInput(),
"policies": FilteredSelectMultiple(_("policies"), False), "policies": FilteredSelectMultiple(_("policies"), False),
} }
help_texts = {
"policies": _(
"Policies which determine if this factor applies to the current user."
)
}

View File

@ -2,7 +2,7 @@
from django import forms from django import forms
from django.conf import settings from django.conf import settings
from django.contrib.admin.widgets import FilteredSelectMultiple from django.contrib.admin.widgets import FilteredSelectMultiple
from django.utils.translation import gettext as _ from django.utils.translation import gettext_lazy as _
from passbook.factors.forms import GENERAL_FIELDS from passbook.factors.forms import GENERAL_FIELDS
from passbook.factors.password.models import PasswordFactor from passbook.factors.password.models import PasswordFactor
@ -49,3 +49,8 @@ class PasswordFactorForm(forms.ModelForm):
"password_policies": FilteredSelectMultiple(_("password policies"), False), "password_policies": FilteredSelectMultiple(_("password policies"), False),
"reset_factors": FilteredSelectMultiple(_("reset factors"), False), "reset_factors": FilteredSelectMultiple(_("reset factors"), False),
} }
help_texts = {
"policies": _(
"Policies which determine if this factor applies to the current user."
)
}

View File

@ -25,18 +25,6 @@ passbook:
password_reset: password_reset:
# Enable password reset, passwords are reset in internal Database and in LDAP if ldap.reset_password is true # Enable password reset, passwords are reset in internal Database and in LDAP if ldap.reset_password is true
enabled: true enabled: true
# Verification the user has to provide in order to be able to reset passwords. Can be any combination of `email`, `2fa`, `security_questions`
verification:
- email
# Text used in title, on login page and multiple other places
branding: passbook
login:
# Override URL used for logo
logo_url: null
# Override URL used for Background on Login page
bg_url: null
# Optionally add a subtext, placed below logo on the login page
subtext: null
footer: footer:
links: links:
# Optionally add links to the footer on the login page # Optionally add links to the footer on the login page
@ -46,14 +34,3 @@ passbook:
uid_fields: uid_fields:
- username - username
- email - email
# Provider-specific settings
ldap:
# Which field from `uid_fields` maps to which LDAP Attribute
login_field_map:
username: sAMAccountName
email: mail # or userPrincipalName
user_attribute_map:
active_directory:
username: "%(sAMAccountName)s"
email: "%(mail)s"
name: "%(displayName)"

View File

@ -1,10 +1,10 @@
"""passbook management command to bootstrap""" """passbook management command to bootstrap"""
from argparse import REMAINDER from argparse import REMAINDER
from subprocess import Popen # nosec from subprocess import Popen # nosec
from sys import stderr, stdin, stdout
# pylint: disable=redefined-builtin from sys import exit as _exit
from sys import exit, stderr, stdin, stdout
from time import sleep from time import sleep
from typing import List
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
from django.db import connection from django.db import connection
@ -54,13 +54,12 @@ class Command(BaseCommand):
should_check = not (self.check_database() and self.check_cache()) should_check = not (self.check_database() and self.check_cache())
sleep(1) sleep(1)
LOGGER.info("Dependencies are up, starting command...") LOGGER.info("Dependencies are up, starting command...")
proc = Popen( commands: List[str] = options.get("command", ["exit", "1"])
args=options.get("command"), stdout=stdout, stderr=stderr, stdin=stdin proc = Popen(args=commands, stdout=stdout, stderr=stderr, stdin=stdin) # nosec
) # nosec
try: try:
proc.wait() proc.wait()
exit(proc.returncode) _exit(proc.returncode)
except KeyboardInterrupt: except KeyboardInterrupt:
LOGGER.info("Killing process") LOGGER.info("Killing process")
proc.kill() proc.kill()
exit(254) _exit(254)

View File

@ -3,11 +3,9 @@ from hashlib import md5
from urllib.parse import urlencode from urllib.parse import urlencode
from django import template from django import template
from django.apps import apps
from django.db.models import Model from django.db.models import Model
from django.template import Context from django.template import Context
from django.utils.html import escape from django.utils.html import escape
from django.utils.translation import ugettext as _
from passbook.lib.config import CONFIG from passbook.lib.config import CONFIG
from passbook.lib.utils.urls import is_url_absolute from passbook.lib.utils.urls import is_url_absolute
@ -40,38 +38,6 @@ def fieldtype(field):
return field.__class__.__name__ return field.__class__.__name__
@register.simple_tag(takes_context=True)
def title(context: Context, *title) -> str:
"""Return either just branding or title - branding"""
branding = CONFIG.y("passbook.branding", "passbook")
if not title:
return branding
if "request" not in context:
return ""
resolver_match = context.request.resolver_match
if not resolver_match:
return ""
# Include App Title in title
app = ""
if resolver_match.namespace != "":
dj_app = None
namespace = context.request.resolver_match.namespace.split(":")[0]
# New label (App URL Namespace == App Label)
dj_app = apps.get_app_config(namespace)
title_modifier = getattr(dj_app, "title_modifier", None)
if title_modifier:
app_title = dj_app.title_modifier(context.request)
app = app_title + " -"
return _(
"%(title)s - %(app)s %(branding)s"
% {
"title": " - ".join([str(x) for x in title]),
"branding": branding,
"app": app,
}
)
@register.simple_tag @register.simple_tag
def config(path, default=""): def config(path, default=""):
"""Get a setting from the database. Returns default is setting doesn't exist.""" """Get a setting from the database. Returns default is setting doesn't exist."""

View File

@ -34,7 +34,7 @@ class ApplicationGatewayProviderSerializer(ModelSerializer):
class Meta: class Meta:
model = ApplicationGatewayProvider model = ApplicationGatewayProvider
fields = ["pk", "name", "host", "client"] fields = ["pk", "name", "internal_host", "external_host", "client"]
read_only_fields = ["client"] read_only_fields = ["client"]

View File

@ -4,7 +4,7 @@
{% load i18n %} {% load i18n %}
{% block card_title %} {% block card_title %}
{% title 'Authorize Application' %} {% trans 'Authorize Application' %}
{% endblock %} {% endblock %}
{% block card %} {% block card %}

View File

@ -1,4 +1,6 @@
"""passbook auth oidc provider app config""" """passbook auth oidc provider app config"""
from importlib import import_module
from django.apps import AppConfig from django.apps import AppConfig
from django.db.utils import InternalError, OperationalError, ProgrammingError from django.db.utils import InternalError, OperationalError, ProgrammingError
from django.urls import include, path from django.urls import include, path
@ -34,3 +36,5 @@ class PassbookProviderOIDCConfig(AppConfig):
include("oidc_provider.urls", namespace="oidc_provider"), include("oidc_provider.urls", namespace="oidc_provider"),
), ),
) )
import_module("passbook.providers.oidc.signals")

View File

@ -0,0 +1,14 @@
"""passbook oidc claim helpers"""
from typing import Any, Dict
from passbook.core.models import User
def userinfo(claims: Dict[str, Any], user: User) -> Dict[str, Any]:
"""Populate claims from userdata"""
claims["name"] = user.name
claims["given_name"] = user.name
claims["family_name"] = user.name
claims["email"] = user.email
return claims

View File

@ -4,5 +4,6 @@ INSTALLED_APPS = [
"oidc_provider", "oidc_provider",
] ]
OIDC_AFTER_USERLOGIN_HOOK = "passbook.providers.oidc.lib.check_permissions" OIDC_AFTER_USERLOGIN_HOOK = "passbook.providers.oidc.auth.check_permissions"
OIDC_IDTOKEN_INCLUDE_CLAIMS = True OIDC_IDTOKEN_INCLUDE_CLAIMS = True
OIDC_USERINFO = "passbook.providers.oidc.claims.userinfo"

View File

@ -0,0 +1,16 @@
"""OIDC Provider signals"""
from django.db.models.signals import post_save
from django.dispatch import receiver
from passbook.core.models import Application
from passbook.providers.oidc.models import OpenIDProvider
@receiver(post_save, sender=Application)
# pylint: disable=unused-argument
def on_application_save(sender, instance: Application, **_):
"""Synchronize application's skip_authorization with oidc_client's require_consent"""
if isinstance(instance.provider, OpenIDProvider):
instance.provider.oidc_client.require_consent = not instance.skip_authorization
instance.provider.oidc_client.save()
print("updating skip_authz")

View File

@ -24,9 +24,7 @@ class SAMLProviderSerializer(ModelSerializer):
"property_mappings", "property_mappings",
"digest_algorithm", "digest_algorithm",
"signature_algorithm", "signature_algorithm",
"signing", "signing_kp",
"signing_cert",
"signing_key",
] ]

View File

@ -9,7 +9,6 @@ from passbook.providers.saml.models import (
SAMLProvider, SAMLProvider,
get_provider_choices, get_provider_choices,
) )
from passbook.providers.saml.utils.cert import CertificateBuilder
class SAMLProviderForm(forms.ModelForm): class SAMLProviderForm(forms.ModelForm):
@ -19,13 +18,6 @@ class SAMLProviderForm(forms.ModelForm):
choices=get_provider_choices(), label="Processor" choices=get_provider_choices(), label="Processor"
) )
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
builder = CertificateBuilder()
builder.build()
self.fields["signing_cert"].initial = builder.certificate
self.fields["signing_key"].initial = builder.private_key
class Meta: class Meta:
model = SAMLProvider model = SAMLProvider
@ -41,9 +33,7 @@ class SAMLProviderForm(forms.ModelForm):
"property_mappings", "property_mappings",
"digest_algorithm", "digest_algorithm",
"signature_algorithm", "signature_algorithm",
"signing", "signing_kp",
"signing_cert",
"signing_key",
] ]
widgets = { widgets = {
"name": forms.TextInput(), "name": forms.TextInput(),

View File

@ -0,0 +1,29 @@
# Generated by Django 3.0.3 on 2020-03-03 21:57
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("passbook_crypto", "0001_initial"),
("passbook_providers_saml", "0006_auto_20200217_2031"),
]
operations = [
migrations.RemoveField(model_name="samlprovider", name="signing",),
migrations.RemoveField(model_name="samlprovider", name="signing_cert",),
migrations.RemoveField(model_name="samlprovider", name="signing_key",),
migrations.AddField(
model_name="samlprovider",
name="singing_kp",
field=models.ForeignKey(
default=None,
help_text="Singing is enabled upon selection of a Key Pair.",
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to="passbook_crypto.CertificateKeyPair",
),
),
]

View File

@ -0,0 +1,16 @@
# Generated by Django 3.0.3 on 2020-03-05 16:06
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("passbook_providers_saml", "0007_auto_20200303_2157"),
]
operations = [
migrations.RenameField(
model_name="samlprovider", old_name="singing_kp", new_name="signing_kp",
),
]

View File

@ -8,6 +8,7 @@ from django.utils.translation import ugettext_lazy as _
from structlog import get_logger from structlog import get_logger
from passbook.core.models import PropertyMapping, Provider from passbook.core.models import PropertyMapping, Provider
from passbook.crypto.models import CertificateKeyPair
from passbook.lib.utils.reflection import class_to_path, path_to_class from passbook.lib.utils.reflection import class_to_path, path_to_class
from passbook.lib.utils.template import render_to_string from passbook.lib.utils.template import render_to_string
from passbook.providers.saml.processors.base import Processor from passbook.providers.saml.processors.base import Processor
@ -74,9 +75,13 @@ class SAMLProvider(Provider):
default="rsa-sha256", default="rsa-sha256",
) )
signing = models.BooleanField(default=True) signing_kp = models.ForeignKey(
signing_cert = models.TextField(verbose_name=_("Singing Certificate")) CertificateKeyPair,
signing_key = models.TextField() default=None,
null=True,
help_text=_("Singing is enabled upon selection of a Key Pair."),
on_delete=models.SET_NULL,
)
form = "passbook.providers.saml.forms.SAMLProviderForm" form = "passbook.providers.saml.forms.SAMLProviderForm"
_processor = None _processor = None

View File

@ -4,7 +4,7 @@
{% load i18n %} {% load i18n %}
{% block card_title %} {% block card_title %}
{% title 'Redirecting...' %} {% trans 'Redirecting...' %}
{% endblock %} {% endblock %}
{% block card %} {% block card %}

View File

@ -31,9 +31,12 @@ def sign_with_signxml(data: str, provider: "SAMLProvider", reference_uri=None) -
digest_algorithm=provider.digest_algorithm, digest_algorithm=provider.digest_algorithm,
) )
signed = signer.sign( signed = signer.sign(
root, key=key, cert=[provider.signing_cert], reference_uri=reference_uri root,
key=key,
cert=[provider.signing_kp.certificate_data],
reference_uri=reference_uri,
) )
XMLVerifier().verify(signed, x509_cert=provider.signing_cert) XMLVerifier().verify(signed, x509_cert=provider.signing_kp.certificate_data)
return etree.tostring(signed).decode("utf-8") # nosec return etree.tostring(signed).decode("utf-8") # nosec

View File

@ -125,6 +125,10 @@ class LoginBeginView(AccessRequiredView):
) )
) )
@method_decorator(csrf_exempt)
def dispatch(self, *args, **kwargs):
return super().dispatch(*args, **kwargs)
@method_decorator(csrf_exempt) @method_decorator(csrf_exempt)
def get(self, request: HttpRequest, application: str) -> HttpResponse: def get(self, request: HttpRequest, application: str) -> HttpResponse:
"""Handle REDIRECT bindings""" """Handle REDIRECT bindings"""
@ -270,9 +274,9 @@ class DescriptorDownloadView(AccessRequiredView):
kwargs={"application": provider.application.slug}, kwargs={"application": provider.application.slug},
) )
) )
pubkey = strip_pem_header(provider.signing_cert.replace("\r", "")).replace( pubkey = strip_pem_header(
"\n", "" provider.signing_kp.certificate_data.replace("\r", "")
) ).replace("\n", "")
subject_format = provider.processor.subject_format subject_format = provider.processor.subject_format
ctx = { ctx = {
"entity_id": entity_id, "entity_id": entity_id,

View File

@ -85,6 +85,7 @@ INSTALLED_APPS = [
"passbook.api.apps.PassbookAPIConfig", "passbook.api.apps.PassbookAPIConfig",
"passbook.lib.apps.PassbookLibConfig", "passbook.lib.apps.PassbookLibConfig",
"passbook.audit.apps.PassbookAuditConfig", "passbook.audit.apps.PassbookAuditConfig",
"passbook.crypto.apps.PassbookCryptoConfig",
"passbook.recovery.apps.PassbookRecoveryConfig", "passbook.recovery.apps.PassbookRecoveryConfig",
"passbook.sources.saml.apps.PassbookSourceSAMLConfig", "passbook.sources.saml.apps.PassbookSourceSAMLConfig",
"passbook.sources.ldap.apps.PassbookSourceLDAPConfig", "passbook.sources.ldap.apps.PassbookSourceLDAPConfig",

View File

@ -17,7 +17,7 @@ class SAMLSourceSerializer(ModelSerializer):
"idp_url", "idp_url",
"idp_logout_url", "idp_logout_url",
"auto_logout", "auto_logout",
"signing_cert", "signing_kp",
] ]

View File

@ -5,19 +5,12 @@ from django.contrib.admin.widgets import FilteredSelectMultiple
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from passbook.admin.forms.source import SOURCE_FORM_FIELDS from passbook.admin.forms.source import SOURCE_FORM_FIELDS
from passbook.providers.saml.utils.cert import CertificateBuilder
from passbook.sources.saml.models import SAMLSource from passbook.sources.saml.models import SAMLSource
class SAMLSourceForm(forms.ModelForm): class SAMLSourceForm(forms.ModelForm):
"""SAML Provider form""" """SAML Provider form"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
builder = CertificateBuilder()
builder.build()
self.fields["signing_cert"].initial = builder.certificate
class Meta: class Meta:
model = SAMLSource model = SAMLSource
@ -26,7 +19,7 @@ class SAMLSourceForm(forms.ModelForm):
"idp_url", "idp_url",
"idp_logout_url", "idp_logout_url",
"auto_logout", "auto_logout",
"signing_cert", "signing_kp",
] ]
widgets = { widgets = {
"name": forms.TextInput(), "name": forms.TextInput(),

View File

@ -0,0 +1,27 @@
# Generated by Django 3.0.3 on 2020-03-03 22:01
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("passbook_crypto", "0001_initial"),
("passbook_sources_saml", "0005_auto_20200220_1621"),
]
operations = [
migrations.RemoveField(model_name="samlsource", name="signing_cert",),
migrations.AddField(
model_name="samlsource",
name="signing_kp",
field=models.ForeignKey(
default=None,
help_text="Certificate Key Pair of the IdP which Assertions are validated against.",
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to="passbook_crypto.CertificateKeyPair",
),
),
]

View File

@ -5,6 +5,7 @@ from django.utils.translation import gettext_lazy as _
from passbook.core.models import Source from passbook.core.models import Source
from passbook.core.types import UILoginButton from passbook.core.types import UILoginButton
from passbook.crypto.models import CertificateKeyPair
class SAMLSource(Source): class SAMLSource(Source):
@ -22,7 +23,16 @@ class SAMLSource(Source):
default=None, blank=True, null=True, verbose_name=_("IDP Logout URL") default=None, blank=True, null=True, verbose_name=_("IDP Logout URL")
) )
auto_logout = models.BooleanField(default=False) auto_logout = models.BooleanField(default=False)
signing_cert = models.TextField()
signing_kp = models.ForeignKey(
CertificateKeyPair,
default=None,
null=True,
help_text=_(
"Certificate Key Pair of the IdP which Assertions are validated against."
),
on_delete=models.SET_NULL,
)
form = "passbook.sources.saml.forms.SAMLSourceForm" form = "passbook.sources.saml.forms.SAMLSourceForm"

View File

@ -46,7 +46,7 @@ class Processor:
def _verify_signed(self): def _verify_signed(self):
"""Verify SAML Response's Signature""" """Verify SAML Response's Signature"""
verifier = XMLVerifier() verifier = XMLVerifier()
verifier.verify(self._root_xml, x509_cert=self._source.signing_cert) verifier.verify(self._root_xml, x509_cert=self._source.signing_kp.certificate)
def _get_email(self) -> Optional[str]: def _get_email(self) -> Optional[str]:
""" """

View File

@ -4,7 +4,7 @@
{% load i18n %} {% load i18n %}
{% block title %} {% block title %}
{% title 'Authorize Application' %} {% trans 'Authorize Application' %}
{% endblock %} {% endblock %}
{% block card %} {% block card %}

View File

@ -101,9 +101,9 @@ class MetadataView(View):
"""Replies with the XML Metadata SPSSODescriptor.""" """Replies with the XML Metadata SPSSODescriptor."""
source: SAMLSource = get_object_or_404(SAMLSource, slug=source_slug) source: SAMLSource = get_object_or_404(SAMLSource, slug=source_slug)
issuer = get_issuer(request, source) issuer = get_issuer(request, source)
cert_stripped = strip_pem_header(source.signing_cert.replace("\r", "")).replace( cert_stripped = strip_pem_header(
"\n", "" source.signing_kp.certificate_data.replace("\r", "")
) ).replace("\n", "")
return render_xml( return render_xml(
request, request,
"saml/sp/xml/sp_sso_descriptor.xml", "saml/sp/xml/sp_sso_descriptor.xml",

View File

@ -1,2 +1,2 @@
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="270px" height="20px" viewBox="0 0 150 10" enable-background="new 0 0 270 10" xml:space="preserve"><defs><style>.cls-1{isolation:isolate;}.cls-2{fill:#fff;}</style></defs><g class="cls-1"><path class="cls-2" d="M1.65,11V2.45H2.87V3a2.81,2.81,0,0,1,.47-.45A1.13,1.13,0,0,1,4,2.38,1.11,1.11,0,0,1,5.1,3a1.55,1.55,0,0,1,.16.5,5.61,5.61,0,0,1,0,.81V6.58c0,.45,0,.77,0,1a1.17,1.17,0,0,1-.55.9,1.23,1.23,0,0,1-.7.16,1.35,1.35,0,0,1-.64-.16A1.53,1.53,0,0,1,2.89,8h0v3ZM4.08,4.43a1.21,1.21,0,0,0-.14-.6.51.51,0,0,0-.46-.22A.54.54,0,0,0,3,3.82a.8.8,0,0,0-.17.54V6.73A.68.68,0,0,0,3,7.2a.6.6,0,0,0,.44.18A.53.53,0,0,0,4,7.17a1,1,0,0,0,.12-.5Z"/><path class="cls-2" d="M8.63,8.54V7.91h0a2.24,2.24,0,0,1-.48.52,1.13,1.13,0,0,1-.69.18A1.39,1.39,0,0,1,7,8.54a1.09,1.09,0,0,1-.43-.24,1.32,1.32,0,0,1-.33-.49A2.33,2.33,0,0,1,6.11,7a4.89,4.89,0,0,1,.08-.91,1.51,1.51,0,0,1,.31-.65,1.44,1.44,0,0,1,.59-.38A3.19,3.19,0,0,1,8,4.93h.59V4.33a1,1,0,0,0-.13-.52A.52.52,0,0,0,8,3.61a.71.71,0,0,0-.44.15.78.78,0,0,0-.26.46H6.13A2,2,0,0,1,6.69,2.9a1.73,1.73,0,0,1,.57-.38A2,2,0,0,1,8,2.38a2.18,2.18,0,0,1,.72.12,1.71,1.71,0,0,1,.59.36,2,2,0,0,1,.38.6,2.18,2.18,0,0,1,.14.84V8.54Zm0-2.62-.34,0a1.2,1.2,0,0,0-.67.18.76.76,0,0,0-.29.68.89.89,0,0,0,.17.56A.55.55,0,0,0,8,7.53a.63.63,0,0,0,.49-.2.91.91,0,0,0,.17-.58Z"/><path class="cls-2" d="M13,4.16a.59.59,0,0,0-.2-.47.65.65,0,0,0-.42-.16.59.59,0,0,0-.45.19.66.66,0,0,0-.15.43.8.8,0,0,0,.08.33.85.85,0,0,0,.44.29l.71.29a1.73,1.73,0,0,1,.95.72,2,2,0,0,1,.26,1,1.85,1.85,0,0,1-.52,1.3,1.56,1.56,0,0,1-.58.39,1.88,1.88,0,0,1-2-.32,1.58,1.58,0,0,1-.4-.57,1.81,1.81,0,0,1-.17-.8h1.15a1.11,1.11,0,0,0,.17.47.56.56,0,0,0,.49.22.71.71,0,0,0,.47-.18A.59.59,0,0,0,13,6.8a.69.69,0,0,0-.13-.43,1.08,1.08,0,0,0-.48-.32l-.59-.21a2.08,2.08,0,0,1-.9-.64,1.66,1.66,0,0,1-.33-1,1.89,1.89,0,0,1,.14-.72,1.78,1.78,0,0,1,.4-.57,1.5,1.5,0,0,1,.56-.36,1.82,1.82,0,0,1,.7-.13,1.93,1.93,0,0,1,.69.13,1.6,1.6,0,0,1,.54.38,1.85,1.85,0,0,1,.36.57,1.82,1.82,0,0,1,.13.7Z"/><path class="cls-2" d="M17.2,4.16a.63.63,0,0,0-.2-.47.69.69,0,0,0-.43-.16.55.55,0,0,0-.44.19.62.62,0,0,0-.16.43.68.68,0,0,0,.09.33.81.81,0,0,0,.43.29l.72.29a1.7,1.7,0,0,1,.94.72,2,2,0,0,1,.26,1,1.85,1.85,0,0,1-.52,1.3,1.61,1.61,0,0,1-.57.39,1.81,1.81,0,0,1-.74.15,1.76,1.76,0,0,1-1.24-.47,1.61,1.61,0,0,1-.41-.57,2,2,0,0,1-.17-.8h1.15a1.12,1.12,0,0,0,.18.47.53.53,0,0,0,.48.22.72.72,0,0,0,.48-.18.59.59,0,0,0,.21-.48.69.69,0,0,0-.14-.43,1,1,0,0,0-.48-.32l-.58-.21a2.06,2.06,0,0,1-.91-.64,1.66,1.66,0,0,1-.33-1A1.89,1.89,0,0,1,15,3.44a1.78,1.78,0,0,1,.4-.57,1.58,1.58,0,0,1,.56-.36,1.82,1.82,0,0,1,.7-.13,1.93,1.93,0,0,1,.69.13,1.75,1.75,0,0,1,.55.38,1.85,1.85,0,0,1,.36.57,2,2,0,0,1,.13.7Z"/><path class="cls-2" d="M19.2,8.54V0h1.22V3h0a1.53,1.53,0,0,1,.48-.47,1.39,1.39,0,0,1,.65-.16,1.26,1.26,0,0,1,.69.16,1.35,1.35,0,0,1,.4.39,1.18,1.18,0,0,1,.15.51,7.72,7.72,0,0,1,0,1V6.73a5.56,5.56,0,0,1-.05.8,1.56,1.56,0,0,1-.15.5,1.12,1.12,0,0,1-1.07.58,1.15,1.15,0,0,1-.7-.18A3.79,3.79,0,0,1,20.42,8v.55Zm2.44-4.21a1,1,0,0,0-.13-.51A.5.5,0,0,0,21,3.61a.57.57,0,0,0-.44.18.66.66,0,0,0-.18.48V6.63a.83.83,0,0,0,.17.54.52.52,0,0,0,.45.21.49.49,0,0,0,.45-.22,1.11,1.11,0,0,0,.15-.6Z"/><path class="cls-2" d="M23.76,4.49a4.83,4.83,0,0,1,0-.68A1.55,1.55,0,0,1,24,3.26a1.59,1.59,0,0,1,.62-.64,1.84,1.84,0,0,1,1-.24,1.87,1.87,0,0,1,1,.24,1.59,1.59,0,0,1,.62.64,1.55,1.55,0,0,1,.18.55,4.83,4.83,0,0,1,.05.68v2a4.72,4.72,0,0,1-.05.68,1.55,1.55,0,0,1-.18.55,1.59,1.59,0,0,1-.62.64,1.87,1.87,0,0,1-1,.24,1.84,1.84,0,0,1-1-.24A1.59,1.59,0,0,1,24,7.73a1.55,1.55,0,0,1-.18-.55,4.72,4.72,0,0,1,0-.68ZM25,6.69a.72.72,0,0,0,.17.52.53.53,0,0,0,.43.17A.55.55,0,0,0,26,7.21a.72.72,0,0,0,.16-.52V4.3A.74.74,0,0,0,26,3.78a.55.55,0,0,0-.44-.17.53.53,0,0,0-.43.17A.74.74,0,0,0,25,4.3Z"/><path class="cls-2" d="M28.2,4.49a4.83,4.83,0,0,1,.05-.68,1.55,1.55,0,0,1,.18-.55,1.59,1.59,0,0,1,.62-.64,1.84,1.84,0,0,1,1-.24,1.87,1.87,0,0,1,1,.24,1.59,1.59,0,0,1,.62.64,1.55,1.55,0,0,1,.18.55,4.83,4.83,0,0,1,.05.68v2a4.72,4.72,0,0,1-.05.68,1.55,1.55,0,0,1-.18.55,1.59,1.59,0,0,1-.62.64,1.87,1.87,0,0,1-1,.24,1.84,1.84,0,0,1-1-.24,1.59,1.59,0,0,1-.62-.64,1.55,1.55,0,0,1-.18-.55,4.72,4.72,0,0,1-.05-.68Zm1.22,2.2a.72.72,0,0,0,.17.52.53.53,0,0,0,.43.17.55.55,0,0,0,.44-.17.72.72,0,0,0,.16-.52V4.3a.74.74,0,0,0-.16-.52A.55.55,0,0,0,30,3.61a.53.53,0,0,0-.43.17.74.74,0,0,0-.17.52Z"/><path class="cls-2" d="M32.75,8.54V0H34V5.11h0l1.47-2.66H36.7L35.24,4.93,37,8.54H35.66l-1.1-2.63L34,6.83V8.54Z"/></g></svg> width="120px" height="20px" viewBox="15 0 10 10" enable-background="new 0 0 270 10" xml:space="preserve"><defs><style>.cls-1{isolation:isolate;}.cls-2{fill:#fff;}</style></defs><g class="cls-1"><path class="cls-2" d="M1.65,11V2.45H2.87V3a2.81,2.81,0,0,1,.47-.45A1.13,1.13,0,0,1,4,2.38,1.11,1.11,0,0,1,5.1,3a1.55,1.55,0,0,1,.16.5,5.61,5.61,0,0,1,0,.81V6.58c0,.45,0,.77,0,1a1.17,1.17,0,0,1-.55.9,1.23,1.23,0,0,1-.7.16,1.35,1.35,0,0,1-.64-.16A1.53,1.53,0,0,1,2.89,8h0v3ZM4.08,4.43a1.21,1.21,0,0,0-.14-.6.51.51,0,0,0-.46-.22A.54.54,0,0,0,3,3.82a.8.8,0,0,0-.17.54V6.73A.68.68,0,0,0,3,7.2a.6.6,0,0,0,.44.18A.53.53,0,0,0,4,7.17a1,1,0,0,0,.12-.5Z"/><path class="cls-2" d="M8.63,8.54V7.91h0a2.24,2.24,0,0,1-.48.52,1.13,1.13,0,0,1-.69.18A1.39,1.39,0,0,1,7,8.54a1.09,1.09,0,0,1-.43-.24,1.32,1.32,0,0,1-.33-.49A2.33,2.33,0,0,1,6.11,7a4.89,4.89,0,0,1,.08-.91,1.51,1.51,0,0,1,.31-.65,1.44,1.44,0,0,1,.59-.38A3.19,3.19,0,0,1,8,4.93h.59V4.33a1,1,0,0,0-.13-.52A.52.52,0,0,0,8,3.61a.71.71,0,0,0-.44.15.78.78,0,0,0-.26.46H6.13A2,2,0,0,1,6.69,2.9a1.73,1.73,0,0,1,.57-.38A2,2,0,0,1,8,2.38a2.18,2.18,0,0,1,.72.12,1.71,1.71,0,0,1,.59.36,2,2,0,0,1,.38.6,2.18,2.18,0,0,1,.14.84V8.54Zm0-2.62-.34,0a1.2,1.2,0,0,0-.67.18.76.76,0,0,0-.29.68.89.89,0,0,0,.17.56A.55.55,0,0,0,8,7.53a.63.63,0,0,0,.49-.2.91.91,0,0,0,.17-.58Z"/><path class="cls-2" d="M13,4.16a.59.59,0,0,0-.2-.47.65.65,0,0,0-.42-.16.59.59,0,0,0-.45.19.66.66,0,0,0-.15.43.8.8,0,0,0,.08.33.85.85,0,0,0,.44.29l.71.29a1.73,1.73,0,0,1,.95.72,2,2,0,0,1,.26,1,1.85,1.85,0,0,1-.52,1.3,1.56,1.56,0,0,1-.58.39,1.88,1.88,0,0,1-2-.32,1.58,1.58,0,0,1-.4-.57,1.81,1.81,0,0,1-.17-.8h1.15a1.11,1.11,0,0,0,.17.47.56.56,0,0,0,.49.22.71.71,0,0,0,.47-.18A.59.59,0,0,0,13,6.8a.69.69,0,0,0-.13-.43,1.08,1.08,0,0,0-.48-.32l-.59-.21a2.08,2.08,0,0,1-.9-.64,1.66,1.66,0,0,1-.33-1,1.89,1.89,0,0,1,.14-.72,1.78,1.78,0,0,1,.4-.57,1.5,1.5,0,0,1,.56-.36,1.82,1.82,0,0,1,.7-.13,1.93,1.93,0,0,1,.69.13,1.6,1.6,0,0,1,.54.38,1.85,1.85,0,0,1,.36.57,1.82,1.82,0,0,1,.13.7Z"/><path class="cls-2" d="M17.2,4.16a.63.63,0,0,0-.2-.47.69.69,0,0,0-.43-.16.55.55,0,0,0-.44.19.62.62,0,0,0-.16.43.68.68,0,0,0,.09.33.81.81,0,0,0,.43.29l.72.29a1.7,1.7,0,0,1,.94.72,2,2,0,0,1,.26,1,1.85,1.85,0,0,1-.52,1.3,1.61,1.61,0,0,1-.57.39,1.81,1.81,0,0,1-.74.15,1.76,1.76,0,0,1-1.24-.47,1.61,1.61,0,0,1-.41-.57,2,2,0,0,1-.17-.8h1.15a1.12,1.12,0,0,0,.18.47.53.53,0,0,0,.48.22.72.72,0,0,0,.48-.18.59.59,0,0,0,.21-.48.69.69,0,0,0-.14-.43,1,1,0,0,0-.48-.32l-.58-.21a2.06,2.06,0,0,1-.91-.64,1.66,1.66,0,0,1-.33-1A1.89,1.89,0,0,1,15,3.44a1.78,1.78,0,0,1,.4-.57,1.58,1.58,0,0,1,.56-.36,1.82,1.82,0,0,1,.7-.13,1.93,1.93,0,0,1,.69.13,1.75,1.75,0,0,1,.55.38,1.85,1.85,0,0,1,.36.57,2,2,0,0,1,.13.7Z"/><path class="cls-2" d="M19.2,8.54V0h1.22V3h0a1.53,1.53,0,0,1,.48-.47,1.39,1.39,0,0,1,.65-.16,1.26,1.26,0,0,1,.69.16,1.35,1.35,0,0,1,.4.39,1.18,1.18,0,0,1,.15.51,7.72,7.72,0,0,1,0,1V6.73a5.56,5.56,0,0,1-.05.8,1.56,1.56,0,0,1-.15.5,1.12,1.12,0,0,1-1.07.58,1.15,1.15,0,0,1-.7-.18A3.79,3.79,0,0,1,20.42,8v.55Zm2.44-4.21a1,1,0,0,0-.13-.51A.5.5,0,0,0,21,3.61a.57.57,0,0,0-.44.18.66.66,0,0,0-.18.48V6.63a.83.83,0,0,0,.17.54.52.52,0,0,0,.45.21.49.49,0,0,0,.45-.22,1.11,1.11,0,0,0,.15-.6Z"/><path class="cls-2" d="M23.76,4.49a4.83,4.83,0,0,1,0-.68A1.55,1.55,0,0,1,24,3.26a1.59,1.59,0,0,1,.62-.64,1.84,1.84,0,0,1,1-.24,1.87,1.87,0,0,1,1,.24,1.59,1.59,0,0,1,.62.64,1.55,1.55,0,0,1,.18.55,4.83,4.83,0,0,1,.05.68v2a4.72,4.72,0,0,1-.05.68,1.55,1.55,0,0,1-.18.55,1.59,1.59,0,0,1-.62.64,1.87,1.87,0,0,1-1,.24,1.84,1.84,0,0,1-1-.24A1.59,1.59,0,0,1,24,7.73a1.55,1.55,0,0,1-.18-.55,4.72,4.72,0,0,1,0-.68ZM25,6.69a.72.72,0,0,0,.17.52.53.53,0,0,0,.43.17A.55.55,0,0,0,26,7.21a.72.72,0,0,0,.16-.52V4.3A.74.74,0,0,0,26,3.78a.55.55,0,0,0-.44-.17.53.53,0,0,0-.43.17A.74.74,0,0,0,25,4.3Z"/><path class="cls-2" d="M28.2,4.49a4.83,4.83,0,0,1,.05-.68,1.55,1.55,0,0,1,.18-.55,1.59,1.59,0,0,1,.62-.64,1.84,1.84,0,0,1,1-.24,1.87,1.87,0,0,1,1,.24,1.59,1.59,0,0,1,.62.64,1.55,1.55,0,0,1,.18.55,4.83,4.83,0,0,1,.05.68v2a4.72,4.72,0,0,1-.05.68,1.55,1.55,0,0,1-.18.55,1.59,1.59,0,0,1-.62.64,1.87,1.87,0,0,1-1,.24,1.84,1.84,0,0,1-1-.24,1.59,1.59,0,0,1-.62-.64,1.55,1.55,0,0,1-.18-.55,4.72,4.72,0,0,1-.05-.68Zm1.22,2.2a.72.72,0,0,0,.17.52.53.53,0,0,0,.43.17.55.55,0,0,0,.44-.17.72.72,0,0,0,.16-.52V4.3a.74.74,0,0,0-.16-.52A.55.55,0,0,0,30,3.61a.53.53,0,0,0-.43.17.74.74,0,0,0-.17.52Z"/><path class="cls-2" d="M32.75,8.54V0H34V5.11h0l1.47-2.66H36.7L35.24,4.93,37,8.54H35.66l-1.1-2.63L34,6.83V8.54Z"/></g></svg>

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@ -197,3 +197,117 @@ form .form-row p.datetime {
input[data-is-monospace] { input[data-is-monospace] {
font-family: monospace; font-family: monospace;
} }
.ws-page-header {
background-color: #151515;
min-height: auto
}
@media (min-width: 992px) {
.ws-page-header .pf-c-page__header-nav {
margin-left:12px
}
}
.ws-page-header .pf-c-nav__scroll-button {
outline-offset: -4px;
height: 100%;
top: 0
}
.ws-page-header .pf-c-nav__horizontal-list .pf-c-nav__item {
margin-right: 0
}
.ws-page-header .pf-c-nav__horizontal-list .pf-c-nav__link {
padding-top: 22px;
padding-right: var(--pf-global--spacer--md);
padding-left: var(--pf-global--spacer--md);
color: var(--pf-global--Color--light-100)
}
@media (max-width: 991px) {
.ws-page-header .pf-c-nav__horizontal-list .pf-c-nav__link {
padding-top:10px
}
}
.ws-page-header .pf-c-nav__horizontal-list .pf-c-nav__link:after {
top: 0!important;
height: 4px
}
.ws-page-header .pf-c-nav__horizontal-list .pf-c-nav__link:active,.ws-page-header .pf-c-nav__horizontal-list .pf-c-nav__link:hover {
-webkit-transition: .5s;
transition: .5s
}
.ws-page-header .pf-c-nav__horizontal-list .pf-c-nav__link.pf-m-current,.ws-page-header .pf-c-nav__horizontal-list .pf-c-nav__link:active,.ws-page-header .pf-c-nav__horizontal-list .pf-c-nav__link:hover {
background-color: var(--pf-global--BackgroundColor--light-100);
color: #151515!important;
font-weight: var(--pf-global--FontWeight--normal)
}
.ws-page-header li a:after {
content: "";
position: absolute;
left: 50%!important;
bottom: 0;
-webkit-transform: translateX(-50%) scaleX(0);
transform: translateX(-50%) scaleX(0);
-webkit-transform-origin: 50% 50%;
transform-origin: 50% 50%;
width: 100%;
height: 1px;
background-color: var(--pf-global--BackgroundColor--light-100);
color: #151515!important;
-webkit-transition: -webkit-transform .25s;
transition: -webkit-transform .25s;
transition: transform .25s;
transition: transform .25s,-webkit-transform .25s
}
.ws-page-header li a:hover:after {
-webkit-transform: translateX(-50%) scaleX(1);
transform: translateX(-50%) scaleX(1)
}
.ws-page-header li a.pf-m-current:after {
left: 0!important;
-webkit-transform: none;
transform: none
}
.ws-page-sidebar#page-sidebar {
color: #fff;
box-shadow: none
}
.ws-page-sidebar .pf-c-nav {
margin-top: 16px
}
.pf-site-search {
padding: 0 0 2px;
width: 150px;
background: transparent;
-webkit-transition: .25s;
transition: .25s
}
.ws-page-header .pf-c-page__header-brand-toggle {
display: none;
visibility: hidden
}
@media (max-width: 768px) {
.pf-site-search {
width:100px
}
.ws-page-header .pf-c-page__header-brand-toggle {
display: block;
visibility: visible
}
}

View File

@ -46,8 +46,3 @@ FROM nginx
COPY --from=static-build /app/static /usr/share/nginx/html/static COPY --from=static-build /app/static /usr/share/nginx/html/static
COPY --from=static-build /app/static/robots.txt /usr/share/nginx/html/robots.txt COPY --from=static-build /app/static/robots.txt /usr/share/nginx/html/robots.txt
COPY --from=npm-packager /static/node_modules /usr/share/nginx/html/static/node_modules COPY --from=npm-packager /static/node_modules /usr/share/nginx/html/static/node_modules
# FROM beryju/pixie:latest
# COPY --from=static-build /app/static /web-root/static/
# COPY --from=static-build /app/static/robots.txt /web-root/robots.txt