Merge branch 'master' into inbuilt-proxy
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> # Conflicts: # internal/constants/constants.go # outpost/pkg/version.go
|
@ -1,5 +1,5 @@
|
||||||
[bumpversion]
|
[bumpversion]
|
||||||
current_version = 2021.6.1-rc6
|
current_version = 2021.6.2
|
||||||
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>.*)
|
||||||
|
|
|
@ -6,6 +6,7 @@ daysUntilClose: 7
|
||||||
exemptLabels:
|
exemptLabels:
|
||||||
- pinned
|
- pinned
|
||||||
- security
|
- security
|
||||||
|
- pr_wanted
|
||||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||||
markComment: >
|
markComment: >
|
||||||
This issue has been automatically marked as stale because it has not had
|
This issue has been automatically marked as stale because it has not had
|
||||||
|
|
|
@ -33,22 +33,21 @@ jobs:
|
||||||
with:
|
with:
|
||||||
push: ${{ github.event_name == 'release' }}
|
push: ${{ github.event_name == 'release' }}
|
||||||
tags: |
|
tags: |
|
||||||
beryju/authentik:2021.6.1-rc6,
|
beryju/authentik:2021.6.2,
|
||||||
beryju/authentik:latest,
|
beryju/authentik:latest,
|
||||||
ghcr.io/goauthentik/server:2021.6.1-rc6,
|
ghcr.io/goauthentik/server:2021.6.2,
|
||||||
ghcr.io/goauthentik/server:latest
|
ghcr.io/goauthentik/server:latest
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
context: .
|
context: .
|
||||||
- name: Building Docker Image (stable)
|
- name: Building Docker Image (stable)
|
||||||
uses: docker/build-push-action@v2
|
if: ${{ github.event_name == 'release' && !contains('2021.6.2', 'rc') }}
|
||||||
if: ${{ github.event_name == 'release' && !contains('2021.6.1-rc6', 'rc') }}
|
run: |
|
||||||
with:
|
docker pull beryju/authentik:latest
|
||||||
push: true
|
docker tag beryju/authentik:latest beryju/authentik:stable
|
||||||
tags: |
|
docker push beryju/authentik:stable
|
||||||
beryju/authentik:stable,
|
docker pull ghcr.io/goauthentik/server:latest
|
||||||
ghcr.io/goauthentik/server:stable
|
docker tag ghcr.io/goauthentik/server:latest ghcr.io/goauthentik/server:stable
|
||||||
platforms: linux/amd64,linux/arm64
|
docker push ghcr.io/goauthentik/server:stable
|
||||||
context: .
|
|
||||||
build-proxy:
|
build-proxy:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
@ -76,22 +75,21 @@ jobs:
|
||||||
with:
|
with:
|
||||||
push: ${{ github.event_name == 'release' }}
|
push: ${{ github.event_name == 'release' }}
|
||||||
tags: |
|
tags: |
|
||||||
beryju/authentik-proxy:2021.6.1-rc6,
|
beryju/authentik-proxy:2021.6.2,
|
||||||
beryju/authentik-proxy:latest,
|
beryju/authentik-proxy:latest,
|
||||||
ghcr.io/goauthentik/proxy:2021.6.1-rc6,
|
ghcr.io/goauthentik/proxy:2021.6.2,
|
||||||
ghcr.io/goauthentik/proxy:latest
|
ghcr.io/goauthentik/proxy:latest
|
||||||
file: proxy.Dockerfile
|
file: proxy.Dockerfile
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
- name: Building Docker Image (stable)
|
- name: Building Docker Image (stable)
|
||||||
uses: docker/build-push-action@v2
|
if: ${{ github.event_name == 'release' && !contains('2021.6.2', 'rc') }}
|
||||||
if: ${{ github.event_name == 'release' && !contains('2021.6.1-rc6', 'rc') }}
|
run: |
|
||||||
with:
|
docker pull beryju/authentik-proxy:latest
|
||||||
push: true
|
docker tag beryju/authentik-proxy:latest beryju/authentik-proxy:stable
|
||||||
tags: |
|
docker push beryju/authentik-proxy:stable
|
||||||
beryju/authentik-proxy:stable,
|
docker pull ghcr.io/goauthentik/proxy:latest
|
||||||
ghcr.io/goauthentik/proxy:stable
|
docker tag ghcr.io/goauthentik/proxy:latest ghcr.io/goauthentik/proxy:stable
|
||||||
platforms: linux/amd64,linux/arm64
|
docker push ghcr.io/goauthentik/proxy:stable
|
||||||
context: .
|
|
||||||
build-ldap:
|
build-ldap:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
@ -119,24 +117,22 @@ jobs:
|
||||||
with:
|
with:
|
||||||
push: ${{ github.event_name == 'release' }}
|
push: ${{ github.event_name == 'release' }}
|
||||||
tags: |
|
tags: |
|
||||||
beryju/authentik-ldap:2021.6.1-rc6,
|
beryju/authentik-ldap:2021.6.2,
|
||||||
beryju/authentik-ldap:latest,
|
beryju/authentik-ldap:latest,
|
||||||
ghcr.io/goauthentik/ldap:2021.6.1-rc6,
|
ghcr.io/goauthentik/ldap:2021.6.2,
|
||||||
ghcr.io/goauthentik/ldap:latest
|
ghcr.io/goauthentik/ldap:latest
|
||||||
file: ldap.Dockerfile
|
file: ldap.Dockerfile
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
- name: Building Docker Image (stable)
|
- name: Building Docker Image (stable)
|
||||||
uses: docker/build-push-action@v2
|
if: ${{ github.event_name == 'release' && !contains('2021.6.2', 'rc') }}
|
||||||
if: ${{ github.event_name == 'release' && !contains('2021.6.1-rc6', 'rc') }}
|
run: |
|
||||||
with:
|
docker pull beryju/authentik-ldap:latest
|
||||||
push: true
|
docker tag beryju/authentik-ldap:latest beryju/authentik-ldap:stable
|
||||||
tags: |
|
docker push beryju/authentik-ldap:stable
|
||||||
beryju/authentik-ldap:stable,
|
docker pull ghcr.io/goauthentik/ldap:latest
|
||||||
ghcr.io/goauthentik/ldap:stable
|
docker tag ghcr.io/goauthentik/ldap:latest ghcr.io/goauthentik/ldap:stable
|
||||||
platforms: linux/amd64,linux/arm64
|
docker push ghcr.io/goauthentik/ldap:stable
|
||||||
context: .
|
|
||||||
test-release:
|
test-release:
|
||||||
if: ${{ github.event_name == 'release' }}
|
|
||||||
needs:
|
needs:
|
||||||
- build-server
|
- build-server
|
||||||
- build-proxy
|
- build-proxy
|
||||||
|
@ -160,13 +156,26 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
- name: Setup Node.js environment
|
||||||
|
uses: actions/setup-node@v2.1.5
|
||||||
|
with:
|
||||||
|
node-version: 12.x
|
||||||
|
- name: Build web api client and web ui
|
||||||
|
run: |
|
||||||
|
export NODE_ENV=production
|
||||||
|
make gen-web
|
||||||
|
cd web
|
||||||
|
npm i
|
||||||
|
npm run build
|
||||||
- name: Create a Sentry.io release
|
- name: Create a Sentry.io release
|
||||||
uses: getsentry/action-release@v1
|
uses: getsentry/action-release@v1
|
||||||
|
if: ${{ github.event_name == 'release' }}
|
||||||
env:
|
env:
|
||||||
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||||
SENTRY_ORG: beryjuorg
|
SENTRY_ORG: beryjuorg
|
||||||
SENTRY_PROJECT: authentik
|
SENTRY_PROJECT: authentik
|
||||||
SENTRY_URL: https://sentry.beryju.org
|
SENTRY_URL: https://sentry.beryju.org
|
||||||
with:
|
with:
|
||||||
version: authentik@2021.6.1-rc6
|
version: authentik@2021.6.2
|
||||||
environment: beryjuorg-prod
|
environment: beryjuorg-prod
|
||||||
|
sourcemaps: './web/dist'
|
||||||
|
|
1
Pipfile
|
@ -46,6 +46,7 @@ webauthn = "*"
|
||||||
xmlsec = "*"
|
xmlsec = "*"
|
||||||
duo-client = "*"
|
duo-client = "*"
|
||||||
ua-parser = "*"
|
ua-parser = "*"
|
||||||
|
deepmerge = "*"
|
||||||
|
|
||||||
[requires]
|
[requires]
|
||||||
python_version = "3.9"
|
python_version = "3.9"
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"_meta": {
|
"_meta": {
|
||||||
"hash": {
|
"hash": {
|
||||||
"sha256": "4fa1ad681762c867a95410074f31ac5d00119e187e0f38982cd59fdf301cccf5"
|
"sha256": "f90d9fb4713eaf9c5ffe6a3858e64843670f79ab5007e7debf914c1f094c8d63"
|
||||||
},
|
},
|
||||||
"pipfile-spec": 6,
|
"pipfile-spec": 6,
|
||||||
"requires": {
|
"requires": {
|
||||||
|
@ -122,19 +122,19 @@
|
||||||
},
|
},
|
||||||
"boto3": {
|
"boto3": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:8e5af9c7ea16ce1c35b7c3220d073dea9735bb1790107820d475462500ae1eff",
|
"sha256:2c2f70608934b03f9c08f4cd185de223b5abd18245dd4d4800e1fbc2a2523e31",
|
||||||
"sha256:e61607211816c194dbe2701db48dcddc87cf19372e6f57a9ebe4dfe93dfe177c"
|
"sha256:fccfa81cda69bb2317ed97e7149d7d84d19e6ec3bfbe3f721139e7ac0c407c73"
|
||||||
],
|
],
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"version": "==1.17.95"
|
"version": "==1.17.98"
|
||||||
},
|
},
|
||||||
"botocore": {
|
"botocore": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:240a9ef007292e986a4e11662f9038435d9d4fd242e083db160c86eb5c24af30",
|
"sha256:b2a49de4ee04b690142c8e7240f0f5758e3f7673dd39cf398efe893bf5e11c3f",
|
||||||
"sha256:dc215f59735a3abde6c66a61f43f10d95bc18754d310da4e2037b3b8c4d8aa2d"
|
"sha256:b955b23fe2fbdbbc8e66f37fe2970de6b5d8169f940b200bcf434751709d38f6"
|
||||||
],
|
],
|
||||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
|
||||||
"version": "==1.20.95"
|
"version": "==1.20.98"
|
||||||
},
|
},
|
||||||
"cachetools": {
|
"cachetools": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
|
@ -165,11 +165,11 @@
|
||||||
},
|
},
|
||||||
"celery": {
|
"celery": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:1329de1edeaf734ef859e630cb42df2c116d53e59d2f46433b13aed196e85620",
|
"sha256:54436cd97b031bf2e08064223240e2a83d601d9414bcb1b702f94c6c33c29485",
|
||||||
"sha256:65f061c04578cf189cd7352c192e1a79fdeb370b916bff792bcc769560e81184"
|
"sha256:b5399d76cf70d5cfac3ec993f8796ec1aa90d4cef55972295751f384758a80d7"
|
||||||
],
|
],
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"version": "==5.1.0"
|
"version": "==5.1.1"
|
||||||
},
|
},
|
||||||
"certifi": {
|
"certifi": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
|
@ -324,6 +324,14 @@
|
||||||
"markers": "python_version >= '3.6'",
|
"markers": "python_version >= '3.6'",
|
||||||
"version": "==3.0.2"
|
"version": "==3.0.2"
|
||||||
},
|
},
|
||||||
|
"deepmerge": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:87166dbe9ba1a3348a45c9d4ada6778f518d41afc0b85aa017ea3041facc3f9c",
|
||||||
|
"sha256:f6fd7f1293c535fb599e197e750dbe8674503c5d2a89759b3c72a3c46746d4fd"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==0.3.0"
|
||||||
|
},
|
||||||
"defusedxml": {
|
"defusedxml": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69",
|
"sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69",
|
||||||
|
@ -465,11 +473,11 @@
|
||||||
},
|
},
|
||||||
"google-auth": {
|
"google-auth": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:154f7889c5d679a6f626f36adb12afbd4dbb0a9a04ec575d989d6ba79c4fd65e",
|
"sha256:b3a67fa9ba5b768861dacf374c2135eb09fa14a0e40c851c3b8ea7abe6fc8fef",
|
||||||
"sha256:6d47c79b5d09fbc7e8355fd9594cc4cf65fdde5d401c63951eaac4baa1ba2ae1"
|
"sha256:e34e5f5de5610b202f9b40ebd9f8b27571d5c5537db9afed3a72b2db5a345039"
|
||||||
],
|
],
|
||||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
|
||||||
"version": "==1.31.0"
|
"version": "==1.32.0"
|
||||||
},
|
},
|
||||||
"gunicorn": {
|
"gunicorn": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
|
@ -786,52 +794,46 @@
|
||||||
},
|
},
|
||||||
"prompt-toolkit": {
|
"prompt-toolkit": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:bf00f22079f5fadc949f42ae8ff7f05702826a97059ffcc6281036ad40ac6f04",
|
"sha256:08360ee3a3148bdb5163621709ee322ec34fc4375099afa4bbf751e9b7b7fa4f",
|
||||||
"sha256:e1b4f11b9336a28fa11810bc623c357420f69dfdb6d2dac41ca2c21a55c033bc"
|
"sha256:7089d8d2938043508aa9420ec18ce0922885304cddae87fb96eebca942299f88"
|
||||||
],
|
],
|
||||||
"markers": "python_full_version >= '3.6.1'",
|
"markers": "python_full_version >= '3.6.1'",
|
||||||
"version": "==3.0.18"
|
"version": "==3.0.19"
|
||||||
},
|
},
|
||||||
"psycopg2-binary": {
|
"psycopg2-binary": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:0deac2af1a587ae12836aa07970f5cb91964f05a7c6cdb69d8425ff4c15d4e2c",
|
"sha256:0b7dae87f0b729922e06f85f667de7bf16455d411971b2043bbd9577af9d1975",
|
||||||
"sha256:0e4dc3d5996760104746e6cfcdb519d9d2cd27c738296525d5867ea695774e67",
|
"sha256:0f2e04bd2a2ab54fa44ee67fe2d002bb90cee1c0f1cc0ebc3148af7b02034cbd",
|
||||||
"sha256:11b9c0ebce097180129e422379b824ae21c8f2a6596b159c7659e2e5a00e1aa0",
|
"sha256:123c3fb684e9abfc47218d3784c7b4c47c8587951ea4dd5bc38b6636ac57f616",
|
||||||
"sha256:15978a1fbd225583dd8cdaf37e67ccc278b5abecb4caf6b2d6b8e2b948e953f6",
|
"sha256:1473c0215b0613dd938db54a653f68251a45a78b05f6fc21af4326f40e8360a2",
|
||||||
"sha256:1fabed9ea2acc4efe4671b92c669a213db744d2af8a9fc5d69a8e9bc14b7a9db",
|
"sha256:14db1752acdd2187d99cb2ca0a1a6dfe57fc65c3281e0f20e597aac8d2a5bd90",
|
||||||
"sha256:2dac98e85565d5688e8ab7bdea5446674a83a3945a8f416ad0110018d1501b94",
|
"sha256:1e3a362790edc0a365385b1ac4cc0acc429a0c0d662d829a50b6ce743ae61b5a",
|
||||||
"sha256:42ec1035841b389e8cc3692277a0bd81cdfe0b65d575a2c8862cec7a80e62e52",
|
"sha256:1e85b74cbbb3056e3656f1cc4781294df03383127a8114cbc6531e8b8367bf1e",
|
||||||
"sha256:6422f2ff0919fd720195f64ffd8f924c1395d30f9a495f31e2392c2efafb5056",
|
"sha256:20f1ab44d8c352074e2d7ca67dc00843067788791be373e67a0911998787ce7d",
|
||||||
"sha256:6a32f3a4cb2f6e1a0b15215f448e8ce2da192fd4ff35084d80d5e39da683e79b",
|
"sha256:2f62c207d1740b0bde5c4e949f857b044818f734a3d57f1d0d0edc65050532ed",
|
||||||
"sha256:7312e931b90fe14f925729cde58022f5d034241918a5c4f9797cac62f6b3a9dd",
|
"sha256:3242b9619de955ab44581a03a64bdd7d5e470cc4183e8fcadd85ab9d3756ce7a",
|
||||||
"sha256:7d92a09b788cbb1aec325af5fcba9fed7203897bbd9269d5691bb1e3bce29550",
|
"sha256:35c4310f8febe41f442d3c65066ca93cccefd75013df3d8c736c5b93ec288140",
|
||||||
"sha256:833709a5c66ca52f1d21d41865a637223b368c0ee76ea54ca5bad6f2526c7679",
|
"sha256:4235f9d5ddcab0b8dbd723dca56ea2922b485ea00e1dafacf33b0c7e840b3d32",
|
||||||
"sha256:89705f45ce07b2dfa806ee84439ec67c5d9a0ef20154e0e475e2b2ed392a5b83",
|
"sha256:5ced67f1e34e1a450cdb48eb53ca73b60aa0af21c46b9b35ac3e581cf9f00e31",
|
||||||
"sha256:8cd0fb36c7412996859cb4606a35969dd01f4ea34d9812a141cd920c3b18be77",
|
"sha256:7360647ea04db2e7dff1648d1da825c8cf68dc5fbd80b8fb5b3ee9f068dcd21a",
|
||||||
"sha256:950bc22bb56ee6ff142a2cb9ee980b571dd0912b0334aa3fe0fe3788d860bea2",
|
"sha256:8c13d72ed6af7fd2c8acbd95661cf9477f94e381fce0792c04981a8283b52917",
|
||||||
"sha256:a0c50db33c32594305b0ef9abc0cb7db13de7621d2cadf8392a1d9b3c437ef77",
|
"sha256:988b47ac70d204aed01589ed342303da7c4d84b56c2f4c4b8b00deda123372bf",
|
||||||
"sha256:a0eb43a07386c3f1f1ebb4dc7aafb13f67188eab896e7397aa1ee95a9c884eb2",
|
"sha256:995fc41ebda5a7a663a254a1dcac52638c3e847f48307b5416ee373da15075d7",
|
||||||
"sha256:aaa4213c862f0ef00022751161df35804127b78adf4a2755b9f991a507e425fd",
|
"sha256:a36c7eb6152ba5467fb264d73844877be8b0847874d4822b7cf2d3c0cb8cdcb0",
|
||||||
"sha256:ac0c682111fbf404525dfc0f18a8b5f11be52657d4f96e9fcb75daf4f3984859",
|
"sha256:aed4a9a7e3221b3e252c39d0bf794c438dc5453bc2963e8befe9d4cd324dff72",
|
||||||
"sha256:ad20d2eb875aaa1ea6d0f2916949f5c08a19c74d05b16ce6ebf6d24f2c9f75d1",
|
"sha256:aef9aee84ec78af51107181d02fe8773b100b01c5dfde351184ad9223eab3698",
|
||||||
"sha256:b4afc542c0ac0db720cf516dd20c0846f71c248d2b3d21013aa0d4ef9c71ca25",
|
"sha256:b0221ca5a9837e040ebf61f48899926b5783668b7807419e4adae8175a31f773",
|
||||||
"sha256:b8a3715b3c4e604bcc94c90a825cd7f5635417453b253499664f784fc4da0152",
|
"sha256:b4d7679a08fea64573c969f6994a2631908bb2c0e69a7235648642f3d2e39a68",
|
||||||
"sha256:ba28584e6bca48c59eecbf7efb1576ca214b47f05194646b081717fa628dfddf",
|
"sha256:c250a7ec489b652c892e4f0a5d122cc14c3780f9f643e1a326754aedf82d9a76",
|
||||||
"sha256:ba381aec3a5dc29634f20692349d73f2d21f17653bda1decf0b52b11d694541f",
|
"sha256:ca86db5b561b894f9e5f115d6a159fff2a2570a652e07889d8a383b5fae66eb4",
|
||||||
"sha256:bd1be66dde2b82f80afb9459fc618216753f67109b859a361cf7def5c7968729",
|
"sha256:cfc523edecddaef56f6740d7de1ce24a2fdf94fd5e704091856a201872e37f9f",
|
||||||
"sha256:c2507d796fca339c8fb03216364cca68d87e037c1f774977c8fc377627d01c71",
|
"sha256:da113b70f6ec40e7d81b43d1b139b9db6a05727ab8be1ee559f3a69854a69d34",
|
||||||
"sha256:cec7e622ebc545dbb4564e483dd20e4e404da17ae07e06f3e780b2dacd5cee66",
|
"sha256:f6fac64a38f6768e7bc7b035b9e10d8a538a9fadce06b983fb3e6fa55ac5f5ce",
|
||||||
"sha256:d14b140a4439d816e3b1229a4a525df917d6ea22a0771a2a78332273fd9528a4",
|
"sha256:f8559617b1fcf59a9aedba2c9838b5b6aa211ffedecabca412b92a1ff75aac1a",
|
||||||
"sha256:d1b4ab59e02d9008efe10ceabd0b31e79519da6fb67f7d8e8977118832d0f449",
|
"sha256:fbb42a541b1093385a2d8c7eec94d26d30437d0e77c1d25dae1dcc46741a385e"
|
||||||
"sha256:d5227b229005a696cc67676e24c214740efd90b148de5733419ac9aaba3773da",
|
|
||||||
"sha256:e1f57aa70d3f7cc6947fd88636a481638263ba04a742b4a37dd25c373e41491a",
|
|
||||||
"sha256:e74a55f6bad0e7d3968399deb50f61f4db1926acf4a6d83beaaa7df986f48b1c",
|
|
||||||
"sha256:e82aba2188b9ba309fd8e271702bd0d0fc9148ae3150532bbb474f4590039ffb",
|
|
||||||
"sha256:ee69dad2c7155756ad114c02db06002f4cded41132cc51378e57aad79cc8e4f4",
|
|
||||||
"sha256:f5ab93a2cb2d8338b1674be43b442a7f544a0971da062a5da774ed40587f18f5"
|
|
||||||
],
|
],
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"version": "==2.8.6"
|
"version": "==2.9.1"
|
||||||
},
|
},
|
||||||
"pyasn1": {
|
"pyasn1": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
|
@ -961,10 +963,10 @@
|
||||||
},
|
},
|
||||||
"python-dotenv": {
|
"python-dotenv": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:00aa34e92d992e9f8383730816359647f358f4a3be1ba45e5a5cefd27ee91544",
|
"sha256:dd8fe852847f4fbfadabf6183ddd4c824a9651f02d51714fa075c95561959c7d",
|
||||||
"sha256:b1ae5e9643d5ed987fc57cc2583021e38db531946518130777734f9589b3141f"
|
"sha256:effaac3c1e58d89b3ccb4d04a40dc7ad6e0275fda25fd75ae9d323e2465e202d"
|
||||||
],
|
],
|
||||||
"version": "==0.17.1"
|
"version": "==0.18.0"
|
||||||
},
|
},
|
||||||
"pytz": {
|
"pytz": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
|
@ -1538,11 +1540,11 @@
|
||||||
},
|
},
|
||||||
"gitpython": {
|
"gitpython": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:3283ae2fba31c913d857e12e5ba5f9a7772bbc064ae2bb09efafa71b0dd4939b",
|
"sha256:b838a895977b45ab6f0cc926a9045c8d1c44e2b653c1fcc39fe91f42c6e8f05b",
|
||||||
"sha256:be27633e7509e58391f10207cd32b2a6cf5b908f92d9cd30da2e514e1137af61"
|
"sha256:fce760879cd2aebd2991b3542876dc5c4a909b30c9d69dfc488e504a8db37ee8"
|
||||||
],
|
],
|
||||||
"markers": "python_version >= '3.4'",
|
"markers": "python_version >= '3.6'",
|
||||||
"version": "==3.1.14"
|
"version": "==3.1.18"
|
||||||
},
|
},
|
||||||
"idna": {
|
"idna": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
|
@ -1560,11 +1562,11 @@
|
||||||
},
|
},
|
||||||
"isort": {
|
"isort": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:0a943902919f65c5684ac4e0154b1ad4fac6dcaa5d9f3426b732f1c8b5419be6",
|
"sha256:83510593e07e433b77bd5bff0f6f607dbafa06d1a89022616f02d8b699cfcd56",
|
||||||
"sha256:2bb1680aad211e3c9944dbce1d4ba09a989f04e238296c87fe2139faa26d655d"
|
"sha256:8e2c107091cfec7286bc0f68a547d0ba4c094d460b732075b6fba674f1035c0c"
|
||||||
],
|
],
|
||||||
"markers": "python_version >= '3.6' and python_version < '4'",
|
"markers": "python_version < '4.0' and python_full_version >= '3.6.1'",
|
||||||
"version": "==5.8.0"
|
"version": "==5.9.1"
|
||||||
},
|
},
|
||||||
"lazy-object-proxy": {
|
"lazy-object-proxy": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
"""authentik"""
|
"""authentik"""
|
||||||
__version__ = "2021.6.1-rc6"
|
__version__ = "2021.6.2"
|
||||||
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"
|
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"
|
||||||
|
|
|
@ -3,23 +3,33 @@ from traceback import format_tb
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from django.http import HttpRequest
|
from django.http import HttpRequest
|
||||||
|
from guardian.utils import get_anonymous_user
|
||||||
|
|
||||||
from authentik.core.models import User
|
from authentik.core.models import PropertyMapping, User
|
||||||
from authentik.events.models import Event, EventAction
|
from authentik.events.models import Event, EventAction
|
||||||
from authentik.lib.expression.evaluator import BaseEvaluator
|
from authentik.lib.expression.evaluator import BaseEvaluator
|
||||||
|
from authentik.policies.types import PolicyRequest
|
||||||
|
|
||||||
|
|
||||||
class PropertyMappingEvaluator(BaseEvaluator):
|
class PropertyMappingEvaluator(BaseEvaluator):
|
||||||
"""Custom Evalautor that adds some different context variables."""
|
"""Custom Evalautor that adds some different context variables."""
|
||||||
|
|
||||||
def set_context(
|
def set_context(
|
||||||
self, user: Optional[User], request: Optional[HttpRequest], **kwargs
|
self,
|
||||||
|
user: Optional[User],
|
||||||
|
request: Optional[HttpRequest],
|
||||||
|
mapping: PropertyMapping,
|
||||||
|
**kwargs,
|
||||||
):
|
):
|
||||||
"""Update context with context from PropertyMapping's evaluate"""
|
"""Update context with context from PropertyMapping's evaluate"""
|
||||||
|
req = PolicyRequest(user=get_anonymous_user())
|
||||||
|
req.obj = mapping
|
||||||
if user:
|
if user:
|
||||||
|
req.user = user
|
||||||
self._context["user"] = user
|
self._context["user"] = user
|
||||||
if request:
|
if request:
|
||||||
self._context["request"] = request
|
req.http_request = request
|
||||||
|
self._context["request"] = req
|
||||||
self._context.update(**kwargs)
|
self._context.update(**kwargs)
|
||||||
|
|
||||||
def handle_error(self, exc: Exception, expression_source: str):
|
def handle_error(self, exc: Exception, expression_source: str):
|
||||||
|
@ -30,9 +40,8 @@ class PropertyMappingEvaluator(BaseEvaluator):
|
||||||
expression=expression_source,
|
expression=expression_source,
|
||||||
message=error_string,
|
message=error_string,
|
||||||
)
|
)
|
||||||
if "user" in self._context:
|
|
||||||
event.set_user(self._context["user"])
|
|
||||||
if "request" in self._context:
|
if "request" in self._context:
|
||||||
event.from_http(self._context["request"])
|
req: PolicyRequest = self._context["request"]
|
||||||
|
event.from_http(req.http_request, req.user)
|
||||||
return
|
return
|
||||||
event.save()
|
event.save()
|
||||||
|
|
|
@ -6,6 +6,7 @@ from urllib.parse import urlencode
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
|
||||||
import django.db.models.options as options
|
import django.db.models.options as options
|
||||||
|
from deepmerge import always_merger
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.models import AbstractUser
|
from django.contrib.auth.models import AbstractUser
|
||||||
from django.contrib.auth.models import UserManager as DjangoUserManager
|
from django.contrib.auth.models import UserManager as DjangoUserManager
|
||||||
|
@ -114,8 +115,8 @@ class User(GuardianUserMixin, AbstractUser):
|
||||||
including the users attributes"""
|
including the users attributes"""
|
||||||
final_attributes = {}
|
final_attributes = {}
|
||||||
for group in self.ak_groups.all().order_by("name"):
|
for group in self.ak_groups.all().order_by("name"):
|
||||||
final_attributes.update(group.attributes)
|
always_merger.merge(final_attributes, group.attributes)
|
||||||
final_attributes.update(self.attributes)
|
always_merger.merge(final_attributes, self.attributes)
|
||||||
return final_attributes
|
return final_attributes
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
|
@ -142,21 +143,25 @@ class User(GuardianUserMixin, AbstractUser):
|
||||||
@property
|
@property
|
||||||
def avatar(self) -> str:
|
def avatar(self) -> str:
|
||||||
"""Get avatar, depending on authentik.avatar setting"""
|
"""Get avatar, depending on authentik.avatar setting"""
|
||||||
mode = CONFIG.raw.get("authentik").get("avatars")
|
mode: str = CONFIG.y("avatars", "none")
|
||||||
if mode == "none":
|
if mode == "none":
|
||||||
return DEFAULT_AVATAR
|
return DEFAULT_AVATAR
|
||||||
|
# gravatar uses md5 for their URLs, so md5 can't be avoided
|
||||||
|
mail_hash = md5(self.email.encode("utf-8")).hexdigest() # nosec
|
||||||
if mode == "gravatar":
|
if mode == "gravatar":
|
||||||
parameters = [
|
parameters = [
|
||||||
("s", "158"),
|
("s", "158"),
|
||||||
("r", "g"),
|
("r", "g"),
|
||||||
]
|
]
|
||||||
# gravatar uses md5 for their URLs, so md5 can't be avoided
|
|
||||||
mail_hash = md5(self.email.encode("utf-8")).hexdigest() # nosec
|
|
||||||
gravatar_url = (
|
gravatar_url = (
|
||||||
f"{GRAVATAR_URL}/avatar/{mail_hash}?{urlencode(parameters, doseq=True)}"
|
f"{GRAVATAR_URL}/avatar/{mail_hash}?{urlencode(parameters, doseq=True)}"
|
||||||
)
|
)
|
||||||
return escape(gravatar_url)
|
return escape(gravatar_url)
|
||||||
raise ValueError(f"Invalid avatar mode {mode}")
|
return mode % {
|
||||||
|
"username": self.username,
|
||||||
|
"mail_hash": mail_hash,
|
||||||
|
"upn": self.attributes.get("upn", ""),
|
||||||
|
}
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
||||||
|
@ -460,7 +465,7 @@ class PropertyMapping(SerializerModel, ManagedModel):
|
||||||
from authentik.core.expression import PropertyMappingEvaluator
|
from authentik.core.expression import PropertyMappingEvaluator
|
||||||
|
|
||||||
evaluator = PropertyMappingEvaluator()
|
evaluator = PropertyMappingEvaluator()
|
||||||
evaluator.set_context(user, request, **kwargs)
|
evaluator.set_context(user, request, self, **kwargs)
|
||||||
try:
|
try:
|
||||||
return evaluator.evaluate(self.expression)
|
return evaluator.evaluate(self.expression)
|
||||||
except (ValueError, SyntaxError) as exc:
|
except (ValueError, SyntaxError) as exc:
|
||||||
|
@ -494,8 +499,12 @@ class AuthenticatedSession(ExpiringModel):
|
||||||
last_used = models.DateTimeField(auto_now=True)
|
last_used = models.DateTimeField(auto_now=True)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_request(request: HttpRequest, user: User) -> "AuthenticatedSession":
|
def from_request(
|
||||||
|
request: HttpRequest, user: User
|
||||||
|
) -> Optional["AuthenticatedSession"]:
|
||||||
"""Create a new session from a http request"""
|
"""Create a new session from a http request"""
|
||||||
|
if not hasattr(request, "session") or not request.session.session_key:
|
||||||
|
return None
|
||||||
return AuthenticatedSession(
|
return AuthenticatedSession(
|
||||||
session_key=request.session.session_key,
|
session_key=request.session.session_key,
|
||||||
user=user,
|
user=user,
|
||||||
|
|
|
@ -49,7 +49,9 @@ def user_logged_in_session(sender, request: HttpRequest, user: "User", **_):
|
||||||
"""Create an AuthenticatedSession from request"""
|
"""Create an AuthenticatedSession from request"""
|
||||||
from authentik.core.models import AuthenticatedSession
|
from authentik.core.models import AuthenticatedSession
|
||||||
|
|
||||||
AuthenticatedSession.from_request(request, user).save()
|
session = AuthenticatedSession.from_request(request, user)
|
||||||
|
if session:
|
||||||
|
session.save()
|
||||||
|
|
||||||
|
|
||||||
@receiver(user_logged_out)
|
@receiver(user_logged_out)
|
||||||
|
|
|
@ -183,6 +183,8 @@ class SourceFlowManager:
|
||||||
# pylint: disable=unused-argument
|
# pylint: disable=unused-argument
|
||||||
def get_stages_to_append(self, flow: Flow) -> list[Stage]:
|
def get_stages_to_append(self, flow: Flow) -> list[Stage]:
|
||||||
"""Hook to override stages which are appended to the flow"""
|
"""Hook to override stages which are appended to the flow"""
|
||||||
|
if not self.source.enrollment_flow:
|
||||||
|
return []
|
||||||
if flow.slug == self.source.enrollment_flow.slug:
|
if flow.slug == self.source.enrollment_flow.slug:
|
||||||
return [
|
return [
|
||||||
in_memory_stage(PostUserEnrollmentStage),
|
in_memory_stage(PostUserEnrollmentStage),
|
||||||
|
|
|
@ -11,6 +11,11 @@
|
||||||
|
|
||||||
{% block head %}
|
{% block head %}
|
||||||
<script src="{% static 'dist/FlowInterface.js' %}?v={{ ak_version }}" type="module"></script>
|
<script src="{% static 'dist/FlowInterface.js' %}?v={{ ak_version }}" type="module"></script>
|
||||||
|
<style>
|
||||||
|
.pf-c-background-image::before {
|
||||||
|
background-image: url("{{ flow.background_url }}");
|
||||||
|
}
|
||||||
|
</style>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
|
|
|
@ -7,6 +7,14 @@
|
||||||
<link rel="stylesheet" type="text/css" href="{% static 'dist/patternfly.min.css' %}?v={{ ak_version }}">
|
<link rel="stylesheet" type="text/css" href="{% static 'dist/patternfly.min.css' %}?v={{ ak_version }}">
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block head %}
|
||||||
|
<style>
|
||||||
|
.pf-c-background-image::before {
|
||||||
|
background-image: url("/static/dist/assets/images/flow_background.jpg");
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
<div class="pf-c-background-image">
|
<div class="pf-c-background-image">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="pf-c-background-image__filter" width="0" height="0">
|
<svg xmlns="http://www.w3.org/2000/svg" class="pf-c-background-image__filter" width="0" height="0">
|
||||||
|
|
|
@ -55,11 +55,16 @@ class CertificateKeyPair(CreatedUpdatedModel):
|
||||||
def private_key(self) -> Optional[RSAPrivateKey]:
|
def private_key(self) -> Optional[RSAPrivateKey]:
|
||||||
"""Get python cryptography PrivateKey instance"""
|
"""Get python cryptography PrivateKey instance"""
|
||||||
if not self._private_key and self._private_key != "":
|
if not self._private_key and self._private_key != "":
|
||||||
|
try:
|
||||||
self._private_key = load_pem_private_key(
|
self._private_key = load_pem_private_key(
|
||||||
str.encode("\n".join([x.strip() for x in self.key_data.split("\n")])),
|
str.encode(
|
||||||
|
"\n".join([x.strip() for x in self.key_data.split("\n")])
|
||||||
|
),
|
||||||
password=None,
|
password=None,
|
||||||
backend=default_backend(),
|
backend=default_backend(),
|
||||||
)
|
)
|
||||||
|
except ValueError:
|
||||||
|
return None
|
||||||
return self._private_key
|
return self._private_key
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
|
@ -14,6 +14,7 @@ from authentik.events.models import cleanse_dict
|
||||||
from authentik.flows.exceptions import EmptyFlowException, FlowNonApplicableException
|
from authentik.flows.exceptions import EmptyFlowException, FlowNonApplicableException
|
||||||
from authentik.flows.markers import ReevaluateMarker, StageMarker
|
from authentik.flows.markers import ReevaluateMarker, StageMarker
|
||||||
from authentik.flows.models import Flow, FlowStageBinding, Stage
|
from authentik.flows.models import Flow, FlowStageBinding, Stage
|
||||||
|
from authentik.lib.config import CONFIG
|
||||||
from authentik.policies.engine import PolicyEngine
|
from authentik.policies.engine import PolicyEngine
|
||||||
from authentik.root.monitoring import UpdatingGauge
|
from authentik.root.monitoring import UpdatingGauge
|
||||||
|
|
||||||
|
@ -33,6 +34,7 @@ HIST_FLOWS_PLAN_TIME = Histogram(
|
||||||
"Duration to build a plan for a flow",
|
"Duration to build a plan for a flow",
|
||||||
["flow_slug"],
|
["flow_slug"],
|
||||||
)
|
)
|
||||||
|
CACHE_TIMEOUT = int(CONFIG.y("redis.cache_timeout_flows"))
|
||||||
|
|
||||||
|
|
||||||
def cache_key(flow: Flow, user: Optional[User] = None) -> str:
|
def cache_key(flow: Flow, user: Optional[User] = None) -> str:
|
||||||
|
@ -157,7 +159,7 @@ class FlowPlanner:
|
||||||
"f(plan): building plan",
|
"f(plan): building plan",
|
||||||
)
|
)
|
||||||
plan = self._build_plan(user, request, default_context)
|
plan = self._build_plan(user, request, default_context)
|
||||||
cache.set(cache_key(self.flow, user), plan)
|
cache.set(cache_key(self.flow, user), plan, CACHE_TIMEOUT)
|
||||||
GAUGE_FLOWS_CACHED.update()
|
GAUGE_FLOWS_CACHED.update()
|
||||||
if not plan.stages and not self.allow_empty_flows:
|
if not plan.stages and not self.allow_empty_flows:
|
||||||
raise EmptyFlowException()
|
raise EmptyFlowException()
|
||||||
|
|
|
@ -18,27 +18,11 @@ from authentik.flows.challenge import (
|
||||||
)
|
)
|
||||||
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER
|
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER
|
||||||
from authentik.flows.views import FlowExecutorView
|
from authentik.flows.views import FlowExecutorView
|
||||||
from authentik.lib.sentry import SentryIgnoredException
|
|
||||||
|
|
||||||
PLAN_CONTEXT_PENDING_USER_IDENTIFIER = "pending_user_identifier"
|
PLAN_CONTEXT_PENDING_USER_IDENTIFIER = "pending_user_identifier"
|
||||||
LOGGER = get_logger()
|
LOGGER = get_logger()
|
||||||
|
|
||||||
|
|
||||||
class InvalidChallengeError(SentryIgnoredException):
|
|
||||||
"""Error raised when a challenge from a stage is not valid"""
|
|
||||||
|
|
||||||
def __init__(self, errors, stage_view: View, challenge: Challenge) -> None:
|
|
||||||
super().__init__()
|
|
||||||
self.errors = errors
|
|
||||||
self.stage_view = stage_view
|
|
||||||
self.challenge = challenge
|
|
||||||
|
|
||||||
def __str__(self) -> str:
|
|
||||||
return (
|
|
||||||
f"Invalid challenge from {self.stage_view}: {self.errors}\n{self.challenge}"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class StageView(View):
|
class StageView(View):
|
||||||
"""Abstract Stage, inherits TemplateView but can be combined with FormView"""
|
"""Abstract Stage, inherits TemplateView but can be combined with FormView"""
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@ from authentik.flows.planner import (
|
||||||
FlowPlan,
|
FlowPlan,
|
||||||
FlowPlanner,
|
FlowPlanner,
|
||||||
)
|
)
|
||||||
|
from authentik.lib.sentry import SentryIgnoredException
|
||||||
from authentik.lib.utils.reflection import all_subclasses, class_to_path
|
from authentik.lib.utils.reflection import all_subclasses, class_to_path
|
||||||
from authentik.lib.utils.urls import is_url_absolute, redirect_with_qs
|
from authentik.lib.utils.urls import is_url_absolute, redirect_with_qs
|
||||||
from authentik.tenants.models import Tenant
|
from authentik.tenants.models import Tenant
|
||||||
|
@ -93,6 +94,10 @@ def challenge_response_types():
|
||||||
return Inner()
|
return Inner()
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidStageError(SentryIgnoredException):
|
||||||
|
"""Error raised when a challenge from a stage is not valid"""
|
||||||
|
|
||||||
|
|
||||||
@method_decorator(xframe_options_sameorigin, name="dispatch")
|
@method_decorator(xframe_options_sameorigin, name="dispatch")
|
||||||
class FlowExecutorView(APIView):
|
class FlowExecutorView(APIView):
|
||||||
"""Stage 1 Flow executor, passing requests to Stage Views"""
|
"""Stage 1 Flow executor, passing requests to Stage Views"""
|
||||||
|
@ -164,12 +169,19 @@ class FlowExecutorView(APIView):
|
||||||
current_stage=self.current_stage,
|
current_stage=self.current_stage,
|
||||||
flow_slug=self.flow.slug,
|
flow_slug=self.flow.slug,
|
||||||
)
|
)
|
||||||
|
try:
|
||||||
stage_cls = self.current_stage.type
|
stage_cls = self.current_stage.type
|
||||||
|
except NotImplementedError as exc:
|
||||||
|
self._logger.debug("Error getting stage type", exc=exc)
|
||||||
|
return self.stage_invalid()
|
||||||
self.current_stage_view = stage_cls(self)
|
self.current_stage_view = stage_cls(self)
|
||||||
self.current_stage_view.args = self.args
|
self.current_stage_view.args = self.args
|
||||||
self.current_stage_view.kwargs = self.kwargs
|
self.current_stage_view.kwargs = self.kwargs
|
||||||
self.current_stage_view.request = request
|
self.current_stage_view.request = request
|
||||||
|
try:
|
||||||
return super().dispatch(request)
|
return super().dispatch(request)
|
||||||
|
except InvalidStageError as exc:
|
||||||
|
return self.stage_invalid(str(exc))
|
||||||
|
|
||||||
@extend_schema(
|
@extend_schema(
|
||||||
responses={
|
responses={
|
||||||
|
@ -353,8 +365,11 @@ class FlowErrorResponse(TemplateResponse):
|
||||||
context = {}
|
context = {}
|
||||||
context["error"] = self.error
|
context["error"] = self.error
|
||||||
if self._request.user and self._request.user.is_authenticated:
|
if self._request.user and self._request.user.is_authenticated:
|
||||||
if self._request.user.is_superuser or self._request.user.attributes.get(
|
if (
|
||||||
|
self._request.user.is_superuser
|
||||||
|
or self._request.user.group_attributes().get(
|
||||||
USER_ATTRIBUTE_DEBUG, False
|
USER_ATTRIBUTE_DEBUG, False
|
||||||
|
)
|
||||||
):
|
):
|
||||||
context["tb"] = "".join(format_tb(self.error.__traceback__))
|
context["tb"] = "".join(format_tb(self.error.__traceback__))
|
||||||
return context
|
return context
|
||||||
|
|
|
@ -62,7 +62,7 @@ class ConfigLoader:
|
||||||
output.update(kwargs)
|
output.update(kwargs)
|
||||||
print(dumps(output))
|
print(dumps(output))
|
||||||
|
|
||||||
def update(self, root, updatee):
|
def update(self, root: dict[str, Any], updatee: dict[str, Any]) -> dict[str, Any]:
|
||||||
"""Recursively update dictionary"""
|
"""Recursively update dictionary"""
|
||||||
for key, value in updatee.items():
|
for key, value in updatee.items():
|
||||||
if isinstance(value, Mapping):
|
if isinstance(value, Mapping):
|
||||||
|
@ -73,7 +73,7 @@ class ConfigLoader:
|
||||||
root[key] = value
|
root[key] = value
|
||||||
return root
|
return root
|
||||||
|
|
||||||
def parse_uri(self, value):
|
def parse_uri(self, value: str) -> str:
|
||||||
"""Parse string values which start with a URI"""
|
"""Parse string values which start with a URI"""
|
||||||
url = urlparse(value)
|
url = urlparse(value)
|
||||||
if url.scheme == "env":
|
if url.scheme == "env":
|
||||||
|
@ -99,7 +99,10 @@ class ConfigLoader:
|
||||||
raise ImproperlyConfigured from exc
|
raise ImproperlyConfigured from exc
|
||||||
except PermissionError as exc:
|
except PermissionError as exc:
|
||||||
self._log(
|
self._log(
|
||||||
"warning", "Permission denied while reading file", path=path, error=exc
|
"warning",
|
||||||
|
"Permission denied while reading file",
|
||||||
|
path=path,
|
||||||
|
error=str(exc),
|
||||||
)
|
)
|
||||||
|
|
||||||
def update_from_dict(self, update: dict):
|
def update_from_dict(self, update: dict):
|
||||||
|
|
|
@ -9,6 +9,7 @@ postgresql:
|
||||||
web:
|
web:
|
||||||
listen: 0.0.0.0:9000
|
listen: 0.0.0.0:9000
|
||||||
listen_tls: 0.0.0.0:9443
|
listen_tls: 0.0.0.0:9443
|
||||||
|
load_local_files: false
|
||||||
|
|
||||||
redis:
|
redis:
|
||||||
host: localhost
|
host: localhost
|
||||||
|
@ -16,6 +17,10 @@ redis:
|
||||||
cache_db: 0
|
cache_db: 0
|
||||||
message_queue_db: 1
|
message_queue_db: 1
|
||||||
ws_db: 2
|
ws_db: 2
|
||||||
|
cache_timeout: 300
|
||||||
|
cache_timeout_flows: 300
|
||||||
|
cache_timeout_policies: 300
|
||||||
|
cache_timeout_reputation: 300
|
||||||
|
|
||||||
debug: false
|
debug: false
|
||||||
|
|
||||||
|
@ -45,10 +50,10 @@ outposts:
|
||||||
# %(build_hash)s: Build hash if you're running a beta version
|
# %(build_hash)s: Build hash if you're running a beta version
|
||||||
docker_image_base: "ghcr.io/goauthentik/%(type)s:%(version)s"
|
docker_image_base: "ghcr.io/goauthentik/%(type)s:%(version)s"
|
||||||
|
|
||||||
authentik:
|
avatars: env://AUTHENTIK_AUTHENTIK__AVATARS?gravatar
|
||||||
avatars: gravatar # gravatar or none
|
|
||||||
geoip: "./GeoLite2-City.mmdb"
|
geoip: "./GeoLite2-City.mmdb"
|
||||||
# Optionally add links to the footer on the login page
|
|
||||||
|
# Can't currently be configured via environment variables, only yaml
|
||||||
footer_links:
|
footer_links:
|
||||||
- name: Documentation
|
- name: Documentation
|
||||||
href: https://goauthentik.io/docs/
|
href: https://goauthentik.io/docs/
|
||||||
|
|
|
@ -3,6 +3,7 @@ import re
|
||||||
from textwrap import indent
|
from textwrap import indent
|
||||||
from typing import Any, Iterable, Optional
|
from typing import Any, Iterable, Optional
|
||||||
|
|
||||||
|
from django.core.exceptions import FieldError
|
||||||
from requests import Session
|
from requests import Session
|
||||||
from rest_framework.serializers import ValidationError
|
from rest_framework.serializers import ValidationError
|
||||||
from sentry_sdk.hub import Hub
|
from sentry_sdk.hub import Hub
|
||||||
|
@ -29,10 +30,10 @@ class BaseEvaluator:
|
||||||
# update website/docs/expressions/_objects.md
|
# update website/docs/expressions/_objects.md
|
||||||
# update website/docs/expressions/_functions.md
|
# update website/docs/expressions/_functions.md
|
||||||
self._globals = {
|
self._globals = {
|
||||||
"regex_match": BaseEvaluator.expr_filter_regex_match,
|
"regex_match": BaseEvaluator.expr_regex_match,
|
||||||
"regex_replace": BaseEvaluator.expr_filter_regex_replace,
|
"regex_replace": BaseEvaluator.expr_regex_replace,
|
||||||
"ak_is_group_member": BaseEvaluator.expr_func_is_group_member,
|
"ak_is_group_member": BaseEvaluator.expr_is_group_member,
|
||||||
"ak_user_by": BaseEvaluator.expr_func_user_by,
|
"ak_user_by": BaseEvaluator.expr_user_by,
|
||||||
"ak_logger": get_logger(),
|
"ak_logger": get_logger(),
|
||||||
"requests": Session(),
|
"requests": Session(),
|
||||||
}
|
}
|
||||||
|
@ -40,25 +41,28 @@ class BaseEvaluator:
|
||||||
self._filename = "BaseEvalautor"
|
self._filename = "BaseEvalautor"
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def expr_filter_regex_match(value: Any, regex: str) -> bool:
|
def expr_regex_match(value: Any, regex: str) -> bool:
|
||||||
"""Expression Filter to run re.search"""
|
"""Expression Filter to run re.search"""
|
||||||
return re.search(regex, value) is None
|
return re.search(regex, value) is not None
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def expr_filter_regex_replace(value: Any, regex: str, repl: str) -> str:
|
def expr_regex_replace(value: Any, regex: str, repl: str) -> str:
|
||||||
"""Expression Filter to run re.sub"""
|
"""Expression Filter to run re.sub"""
|
||||||
return re.sub(regex, repl, value)
|
return re.sub(regex, repl, value)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def expr_func_user_by(**filters) -> Optional[User]:
|
def expr_user_by(**filters) -> Optional[User]:
|
||||||
"""Get user by filters"""
|
"""Get user by filters"""
|
||||||
|
try:
|
||||||
users = User.objects.filter(**filters)
|
users = User.objects.filter(**filters)
|
||||||
if users:
|
if users:
|
||||||
return users.first()
|
return users.first()
|
||||||
return None
|
return None
|
||||||
|
except FieldError:
|
||||||
|
return None
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def expr_func_is_group_member(user: User, **group_filters) -> bool:
|
def expr_is_group_member(user: User, **group_filters) -> bool:
|
||||||
"""Check if `user` is member of group with name `group_name`"""
|
"""Check if `user` is member of group with name `group_name`"""
|
||||||
return user.ak_groups.filter(**group_filters).exists()
|
return user.ak_groups.filter(**group_filters).exists()
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
"""Test config loader"""
|
||||||
|
from os import chmod, environ, unlink, write
|
||||||
|
from tempfile import mkstemp
|
||||||
|
|
||||||
|
from django.conf import ImproperlyConfigured
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
from authentik.lib.config import ENV_PREFIX, ConfigLoader
|
||||||
|
|
||||||
|
|
||||||
|
class TestConfig(TestCase):
|
||||||
|
"""Test config loader"""
|
||||||
|
|
||||||
|
def test_env(self):
|
||||||
|
"""Test simple instance"""
|
||||||
|
config = ConfigLoader()
|
||||||
|
environ[ENV_PREFIX + "_test__test"] = "bar"
|
||||||
|
config.update_from_env()
|
||||||
|
self.assertEqual(config.y("test.test"), "bar")
|
||||||
|
|
||||||
|
def test_patch(self):
|
||||||
|
"""Test patch decorator"""
|
||||||
|
config = ConfigLoader()
|
||||||
|
config.y_set("foo.bar", "bar")
|
||||||
|
self.assertEqual(config.y("foo.bar"), "bar")
|
||||||
|
with config.patch("foo.bar", "baz"):
|
||||||
|
self.assertEqual(config.y("foo.bar"), "baz")
|
||||||
|
self.assertEqual(config.y("foo.bar"), "bar")
|
||||||
|
|
||||||
|
def test_uri_env(self):
|
||||||
|
"""Test URI parsing (environment)"""
|
||||||
|
config = ConfigLoader()
|
||||||
|
environ["foo"] = "bar"
|
||||||
|
self.assertEqual(config.parse_uri("env://foo"), "bar")
|
||||||
|
self.assertEqual(config.parse_uri("env://fo?bar"), "bar")
|
||||||
|
|
||||||
|
def test_uri_file(self):
|
||||||
|
"""Test URI parsing (file load)"""
|
||||||
|
config = ConfigLoader()
|
||||||
|
file, file_name = mkstemp()
|
||||||
|
write(file, "foo".encode())
|
||||||
|
_, file2_name = mkstemp()
|
||||||
|
chmod(file2_name, 0o000) # Remove all permissions so we can't read the file
|
||||||
|
self.assertEqual(config.parse_uri(f"file://{file_name}"), "foo")
|
||||||
|
self.assertEqual(config.parse_uri(f"file://{file2_name}?def"), "def")
|
||||||
|
unlink(file_name)
|
||||||
|
unlink(file2_name)
|
||||||
|
|
||||||
|
def test_file_update(self):
|
||||||
|
"""Test update_from_file"""
|
||||||
|
config = ConfigLoader()
|
||||||
|
file, file_name = mkstemp()
|
||||||
|
write(file, "{".encode())
|
||||||
|
file2, file2_name = mkstemp()
|
||||||
|
write(file2, "{".encode())
|
||||||
|
chmod(file2_name, 0o000) # Remove all permissions so we can't read the file
|
||||||
|
with self.assertRaises(ImproperlyConfigured):
|
||||||
|
config.update_from_file(file_name)
|
||||||
|
config.update_from_file(file2_name)
|
||||||
|
unlink(file_name)
|
||||||
|
unlink(file2_name)
|
|
@ -0,0 +1,32 @@
|
||||||
|
"""Test Evaluator base functions"""
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
from authentik.core.models import User
|
||||||
|
from authentik.lib.expression.evaluator import BaseEvaluator
|
||||||
|
|
||||||
|
|
||||||
|
class TestEvaluator(TestCase):
|
||||||
|
"""Test Evaluator base functions"""
|
||||||
|
|
||||||
|
def test_regex_match(self):
|
||||||
|
"""Test expr_regex_match"""
|
||||||
|
self.assertFalse(BaseEvaluator.expr_regex_match("foo", "bar"))
|
||||||
|
self.assertTrue(BaseEvaluator.expr_regex_match("foo", "foo"))
|
||||||
|
|
||||||
|
def test_regex_replace(self):
|
||||||
|
"""Test expr_regex_replace"""
|
||||||
|
self.assertEqual(BaseEvaluator.expr_regex_replace("foo", "o", "a"), "faa")
|
||||||
|
|
||||||
|
def test_user_by(self):
|
||||||
|
"""Test expr_user_by"""
|
||||||
|
self.assertIsNotNone(BaseEvaluator.expr_user_by(username="akadmin"))
|
||||||
|
self.assertIsNone(BaseEvaluator.expr_user_by(username="bar"))
|
||||||
|
self.assertIsNone(BaseEvaluator.expr_user_by(foo="bar"))
|
||||||
|
|
||||||
|
def test_is_group_member(self):
|
||||||
|
"""Test expr_is_group_member"""
|
||||||
|
self.assertFalse(
|
||||||
|
BaseEvaluator.expr_is_group_member(
|
||||||
|
User.objects.get(username="akadmin"), name="test"
|
||||||
|
)
|
||||||
|
)
|
|
@ -33,7 +33,7 @@ def _get_outpost_override_ip(request: HttpRequest) -> Optional[str]:
|
||||||
return None
|
return None
|
||||||
if OUTPOST_REMOTE_IP_HEADER not in request.META:
|
if OUTPOST_REMOTE_IP_HEADER not in request.META:
|
||||||
return None
|
return None
|
||||||
if request.user.attributes.get(USER_ATTRIBUTE_CAN_OVERRIDE_IP, False):
|
if request.user.group_attributes().get(USER_ATTRIBUTE_CAN_OVERRIDE_IP, False):
|
||||||
return None
|
return None
|
||||||
return request.META[OUTPOST_REMOTE_IP_HEADER]
|
return request.META[OUTPOST_REMOTE_IP_HEADER]
|
||||||
|
|
||||||
|
|
|
@ -67,11 +67,6 @@ class OutpostConsumer(AuthJsonConsumer):
|
||||||
self.accept()
|
self.accept()
|
||||||
self.outpost = outpost.first()
|
self.outpost = outpost.first()
|
||||||
self.last_uid = self.channel_name
|
self.last_uid = self.channel_name
|
||||||
LOGGER.debug(
|
|
||||||
"added outpost instace to cache",
|
|
||||||
outpost=self.outpost,
|
|
||||||
channel_name=self.channel_name,
|
|
||||||
)
|
|
||||||
|
|
||||||
# pylint: disable=unused-argument
|
# pylint: disable=unused-argument
|
||||||
def disconnect(self, close_code):
|
def disconnect(self, close_code):
|
||||||
|
@ -108,6 +103,11 @@ class OutpostConsumer(AuthJsonConsumer):
|
||||||
outpost=self.outpost.name,
|
outpost=self.outpost.name,
|
||||||
uid=self.last_uid,
|
uid=self.last_uid,
|
||||||
).inc()
|
).inc()
|
||||||
|
LOGGER.debug(
|
||||||
|
"added outpost instace to cache",
|
||||||
|
outpost=self.outpost,
|
||||||
|
instance_uuid=self.last_uid,
|
||||||
|
)
|
||||||
self.first_msg = True
|
self.first_msg = True
|
||||||
|
|
||||||
if msg.instruction == WebsocketMessageInstruction.HELLO:
|
if msg.instruction == WebsocketMessageInstruction.HELLO:
|
||||||
|
|
|
@ -66,7 +66,7 @@ class DockerController(BaseController):
|
||||||
"name": container_name,
|
"name": container_name,
|
||||||
"detach": True,
|
"detach": True,
|
||||||
"ports": {
|
"ports": {
|
||||||
f"{port.port}/{port.protocol.lower()}": port.inner_port or port.port
|
f"{port.inner_port or port.port}/{port.protocol.lower()}": port.port
|
||||||
for port in self.deployment_ports
|
for port in self.deployment_ports
|
||||||
},
|
},
|
||||||
"environment": self._get_env(),
|
"environment": self._get_env(),
|
||||||
|
|
|
@ -37,7 +37,9 @@ class AccessDeniedResponse(TemplateResponse):
|
||||||
if self._request.user and self._request.user.is_authenticated:
|
if self._request.user and self._request.user.is_authenticated:
|
||||||
if (
|
if (
|
||||||
self._request.user.is_superuser
|
self._request.user.is_superuser
|
||||||
or self._request.user.attributes.get(USER_ATTRIBUTE_DEBUG, False)
|
or self._request.user.group_attributes().get(
|
||||||
|
USER_ATTRIBUTE_DEBUG, False
|
||||||
|
)
|
||||||
):
|
):
|
||||||
context["policy_result"] = self.policy_result
|
context["policy_result"] = self.policy_result
|
||||||
return context
|
return context
|
||||||
|
|
|
@ -10,6 +10,7 @@ from sentry_sdk.tracing import Span
|
||||||
from structlog.stdlib import get_logger
|
from structlog.stdlib import get_logger
|
||||||
|
|
||||||
from authentik.events.models import Event, EventAction
|
from authentik.events.models import Event, EventAction
|
||||||
|
from authentik.lib.config import CONFIG
|
||||||
from authentik.lib.utils.errors import exception_to_string
|
from authentik.lib.utils.errors import exception_to_string
|
||||||
from authentik.policies.exceptions import PolicyException
|
from authentik.policies.exceptions import PolicyException
|
||||||
from authentik.policies.models import PolicyBinding
|
from authentik.policies.models import PolicyBinding
|
||||||
|
@ -18,6 +19,7 @@ from authentik.policies.types import PolicyRequest, PolicyResult
|
||||||
LOGGER = get_logger()
|
LOGGER = get_logger()
|
||||||
|
|
||||||
FORK_CTX = get_context("fork")
|
FORK_CTX = get_context("fork")
|
||||||
|
CACHE_TIMEOUT = int(CONFIG.y("redis.cache_timeout_policies"))
|
||||||
PROCESS_CLASS = FORK_CTX.Process
|
PROCESS_CLASS = FORK_CTX.Process
|
||||||
HIST_POLICIES_EXECUTION_TIME = Histogram(
|
HIST_POLICIES_EXECUTION_TIME = Histogram(
|
||||||
"authentik_policies_execution_time",
|
"authentik_policies_execution_time",
|
||||||
|
@ -114,7 +116,7 @@ class PolicyProcess(PROCESS_CLASS):
|
||||||
policy_result.source_binding = self.binding
|
policy_result.source_binding = self.binding
|
||||||
if not self.request.debug:
|
if not self.request.debug:
|
||||||
key = cache_key(self.binding, self.request)
|
key = cache_key(self.binding, self.request)
|
||||||
cache.set(key, policy_result)
|
cache.set(key, policy_result, CACHE_TIMEOUT)
|
||||||
LOGGER.debug(
|
LOGGER.debug(
|
||||||
"P_ENG(proc): finished and cached ",
|
"P_ENG(proc): finished and cached ",
|
||||||
policy=self.binding.policy,
|
policy=self.binding.policy,
|
||||||
|
|
|
@ -5,6 +5,7 @@ from django.dispatch import receiver
|
||||||
from django.http import HttpRequest
|
from django.http import HttpRequest
|
||||||
from structlog.stdlib import get_logger
|
from structlog.stdlib import get_logger
|
||||||
|
|
||||||
|
from authentik.lib.config import CONFIG
|
||||||
from authentik.lib.utils.http import get_client_ip
|
from authentik.lib.utils.http import get_client_ip
|
||||||
from authentik.policies.reputation.models import (
|
from authentik.policies.reputation.models import (
|
||||||
CACHE_KEY_IP_PREFIX,
|
CACHE_KEY_IP_PREFIX,
|
||||||
|
@ -13,6 +14,7 @@ from authentik.policies.reputation.models import (
|
||||||
from authentik.stages.identification.signals import identification_failed
|
from authentik.stages.identification.signals import identification_failed
|
||||||
|
|
||||||
LOGGER = get_logger()
|
LOGGER = get_logger()
|
||||||
|
CACHE_TIMEOUT = int(CONFIG.y("redis.cache_timeout_reputation"))
|
||||||
|
|
||||||
|
|
||||||
def update_score(request: HttpRequest, username: str, amount: int):
|
def update_score(request: HttpRequest, username: str, amount: int):
|
||||||
|
@ -20,10 +22,10 @@ def update_score(request: HttpRequest, username: str, amount: int):
|
||||||
remote_ip = get_client_ip(request)
|
remote_ip = get_client_ip(request)
|
||||||
|
|
||||||
# We only update the cache here, as its faster than writing to the DB
|
# We only update the cache here, as its faster than writing to the DB
|
||||||
cache.get_or_set(CACHE_KEY_IP_PREFIX + remote_ip, 0)
|
cache.get_or_set(CACHE_KEY_IP_PREFIX + remote_ip, 0, CACHE_TIMEOUT)
|
||||||
cache.incr(CACHE_KEY_IP_PREFIX + remote_ip, amount)
|
cache.incr(CACHE_KEY_IP_PREFIX + remote_ip, amount)
|
||||||
|
|
||||||
cache.get_or_set(CACHE_KEY_USER_PREFIX + username, 0)
|
cache.get_or_set(CACHE_KEY_USER_PREFIX + username, 0, CACHE_TIMEOUT)
|
||||||
cache.incr(CACHE_KEY_USER_PREFIX + username, amount)
|
cache.incr(CACHE_KEY_USER_PREFIX + username, amount)
|
||||||
|
|
||||||
LOGGER.debug("Updated score", amount=amount, for_user=username, for_ip=remote_ip)
|
LOGGER.debug("Updated score", amount=amount, for_user=username, for_ip=remote_ip)
|
||||||
|
|
|
@ -105,6 +105,7 @@ class PolicyAccessView(AccessMixin, View):
|
||||||
policy_engine = PolicyEngine(
|
policy_engine = PolicyEngine(
|
||||||
self.application, user or self.request.user, self.request
|
self.application, user or self.request.user, self.request
|
||||||
)
|
)
|
||||||
|
policy_engine.use_cache = False
|
||||||
policy_engine.build()
|
policy_engine.build()
|
||||||
result = policy_engine.result
|
result = policy_engine.result
|
||||||
LOGGER.debug(
|
LOGGER.debug(
|
||||||
|
|
|
@ -9,7 +9,7 @@ return {}
|
||||||
"""
|
"""
|
||||||
SCOPE_EMAIL_EXPRESSION = """
|
SCOPE_EMAIL_EXPRESSION = """
|
||||||
return {
|
return {
|
||||||
"email": user.email,
|
"email": request.user.email,
|
||||||
"email_verified": True
|
"email_verified": True
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
|
@ -17,14 +17,14 @@ SCOPE_PROFILE_EXPRESSION = """
|
||||||
return {
|
return {
|
||||||
# Because authentik only saves the user's full name, and has no concept of first and last names,
|
# Because authentik only saves the user's full name, and has no concept of first and last names,
|
||||||
# the full name is used as given name.
|
# the full name is used as given name.
|
||||||
# You can override this behaviour in custom mappings, i.e. `user.name.split(" ")`
|
# You can override this behaviour in custom mappings, i.e. `request.user.name.split(" ")`
|
||||||
"name": user.name,
|
"name": request.user.name,
|
||||||
"given_name": user.name,
|
"given_name": request.user.name,
|
||||||
"family_name": "",
|
"family_name": "",
|
||||||
"preferred_username": user.username,
|
"preferred_username": request.user.username,
|
||||||
"nickname": user.username,
|
"nickname": request.user.username,
|
||||||
# groups is not part of the official userinfo schema, but is a quasi-standard
|
# groups is not part of the official userinfo schema, but is a quasi-standard
|
||||||
"groups": [group.name for group in user.ak_groups.all()],
|
"groups": [group.name for group in request.user.ak_groups.all()],
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ SCOPE_AK_PROXY_EXPRESSION = """
|
||||||
# which are used for example for the HTTP-Basic Authentication mapping.
|
# which are used for example for the HTTP-Basic Authentication mapping.
|
||||||
return {
|
return {
|
||||||
"ak_proxy": {
|
"ak_proxy": {
|
||||||
"user_attributes": user.group_attributes()
|
"user_attributes": request.user.group_attributes()
|
||||||
}
|
}
|
||||||
}"""
|
}"""
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ from authentik.managed.manager import EnsureExists, ObjectManager
|
||||||
from authentik.providers.saml.models import SAMLPropertyMapping
|
from authentik.providers.saml.models import SAMLPropertyMapping
|
||||||
|
|
||||||
GROUP_EXPRESSION = """
|
GROUP_EXPRESSION = """
|
||||||
for group in user.ak_groups.all():
|
for group in request.user.ak_groups.all():
|
||||||
yield group.name
|
yield group.name
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ class SAMLProviderManager(ObjectManager):
|
||||||
"goauthentik.io/providers/saml/upn",
|
"goauthentik.io/providers/saml/upn",
|
||||||
name="authentik default SAML Mapping: UPN",
|
name="authentik default SAML Mapping: UPN",
|
||||||
saml_name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn",
|
saml_name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn",
|
||||||
expression="return user.attributes.get('upn', user.email)",
|
expression="return request.user.attributes.get('upn', request.user.email)",
|
||||||
friendly_name="",
|
friendly_name="",
|
||||||
),
|
),
|
||||||
EnsureExists(
|
EnsureExists(
|
||||||
|
@ -26,7 +26,7 @@ class SAMLProviderManager(ObjectManager):
|
||||||
"goauthentik.io/providers/saml/name",
|
"goauthentik.io/providers/saml/name",
|
||||||
name="authentik default SAML Mapping: Name",
|
name="authentik default SAML Mapping: Name",
|
||||||
saml_name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name",
|
saml_name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name",
|
||||||
expression="return user.name",
|
expression="return request.user.name",
|
||||||
friendly_name="",
|
friendly_name="",
|
||||||
),
|
),
|
||||||
EnsureExists(
|
EnsureExists(
|
||||||
|
@ -34,7 +34,7 @@ class SAMLProviderManager(ObjectManager):
|
||||||
"goauthentik.io/providers/saml/email",
|
"goauthentik.io/providers/saml/email",
|
||||||
name="authentik default SAML Mapping: Email",
|
name="authentik default SAML Mapping: Email",
|
||||||
saml_name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress",
|
saml_name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress",
|
||||||
expression="return user.email",
|
expression="return request.user.email",
|
||||||
friendly_name="",
|
friendly_name="",
|
||||||
),
|
),
|
||||||
EnsureExists(
|
EnsureExists(
|
||||||
|
@ -42,7 +42,7 @@ class SAMLProviderManager(ObjectManager):
|
||||||
"goauthentik.io/providers/saml/username",
|
"goauthentik.io/providers/saml/username",
|
||||||
name="authentik default SAML Mapping: Username",
|
name="authentik default SAML Mapping: Username",
|
||||||
saml_name="http://schemas.goauthentik.io/2021/02/saml/username",
|
saml_name="http://schemas.goauthentik.io/2021/02/saml/username",
|
||||||
expression="return user.username",
|
expression="return request.user.username",
|
||||||
friendly_name="",
|
friendly_name="",
|
||||||
),
|
),
|
||||||
EnsureExists(
|
EnsureExists(
|
||||||
|
@ -50,7 +50,7 @@ class SAMLProviderManager(ObjectManager):
|
||||||
"goauthentik.io/providers/saml/uid",
|
"goauthentik.io/providers/saml/uid",
|
||||||
name="authentik default SAML Mapping: User ID",
|
name="authentik default SAML Mapping: User ID",
|
||||||
saml_name="http://schemas.goauthentik.io/2021/02/saml/uid",
|
saml_name="http://schemas.goauthentik.io/2021/02/saml/uid",
|
||||||
expression="return user.pk",
|
expression="return request.user.pk",
|
||||||
friendly_name="",
|
friendly_name="",
|
||||||
),
|
),
|
||||||
EnsureExists(
|
EnsureExists(
|
||||||
|
@ -68,7 +68,7 @@ class SAMLProviderManager(ObjectManager):
|
||||||
saml_name=(
|
saml_name=(
|
||||||
"http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname"
|
"http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname"
|
||||||
),
|
),
|
||||||
expression="return user.username",
|
expression="return request.user.username",
|
||||||
friendly_name="",
|
friendly_name="",
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -24,6 +24,7 @@ from authentik.sources.saml.processors.constants import (
|
||||||
SAML_NAME_ID_FORMAT_EMAIL,
|
SAML_NAME_ID_FORMAT_EMAIL,
|
||||||
SAML_NAME_ID_FORMAT_PERSISTENT,
|
SAML_NAME_ID_FORMAT_PERSISTENT,
|
||||||
SAML_NAME_ID_FORMAT_TRANSIENT,
|
SAML_NAME_ID_FORMAT_TRANSIENT,
|
||||||
|
SAML_NAME_ID_FORMAT_UNSPECIFIED,
|
||||||
SAML_NAME_ID_FORMAT_WINDOWS,
|
SAML_NAME_ID_FORMAT_WINDOWS,
|
||||||
SAML_NAME_ID_FORMAT_X509,
|
SAML_NAME_ID_FORMAT_X509,
|
||||||
SIGN_ALGORITHM_TRANSFORM_MAP,
|
SIGN_ALGORITHM_TRANSFORM_MAP,
|
||||||
|
@ -165,7 +166,10 @@ class AssertionProcessor:
|
||||||
if name_id.attrib["Format"] == SAML_NAME_ID_FORMAT_EMAIL:
|
if name_id.attrib["Format"] == SAML_NAME_ID_FORMAT_EMAIL:
|
||||||
name_id.text = self.http_request.user.email
|
name_id.text = self.http_request.user.email
|
||||||
return name_id
|
return name_id
|
||||||
if name_id.attrib["Format"] == SAML_NAME_ID_FORMAT_PERSISTENT:
|
if name_id.attrib["Format"] in [
|
||||||
|
SAML_NAME_ID_FORMAT_PERSISTENT,
|
||||||
|
SAML_NAME_ID_FORMAT_UNSPECIFIED,
|
||||||
|
]:
|
||||||
name_id.text = persistent
|
name_id.text = persistent
|
||||||
return name_id
|
return name_id
|
||||||
if name_id.attrib["Format"] == SAML_NAME_ID_FORMAT_X509:
|
if name_id.attrib["Format"] == SAML_NAME_ID_FORMAT_X509:
|
||||||
|
@ -180,7 +184,7 @@ class AssertionProcessor:
|
||||||
return name_id
|
return name_id
|
||||||
if name_id.attrib["Format"] == SAML_NAME_ID_FORMAT_TRANSIENT:
|
if name_id.attrib["Format"] == SAML_NAME_ID_FORMAT_TRANSIENT:
|
||||||
# Use the hash of the user's session, which changes every session
|
# Use the hash of the user's session, which changes every session
|
||||||
session_key: str = self.http_request.user.session.session_key
|
session_key: str = self.http_request.session.session_key
|
||||||
name_id.text = sha256(session_key.encode()).hexdigest()
|
name_id.text = sha256(session_key.encode()).hexdigest()
|
||||||
return name_id
|
return name_id
|
||||||
raise UnsupportedNameIDFormat(
|
raise UnsupportedNameIDFormat(
|
||||||
|
|
|
@ -20,10 +20,11 @@ from authentik.sources.saml.processors.constants import (
|
||||||
RSA_SHA256,
|
RSA_SHA256,
|
||||||
RSA_SHA384,
|
RSA_SHA384,
|
||||||
RSA_SHA512,
|
RSA_SHA512,
|
||||||
SAML_NAME_ID_FORMAT_EMAIL,
|
SAML_NAME_ID_FORMAT_UNSPECIFIED,
|
||||||
)
|
)
|
||||||
|
|
||||||
LOGGER = get_logger()
|
LOGGER = get_logger()
|
||||||
|
ERROR_CANNOT_DECODE_REQUEST = "Cannot decode SAML request."
|
||||||
ERROR_SIGNATURE_REQUIRED_BUT_ABSENT = (
|
ERROR_SIGNATURE_REQUIRED_BUT_ABSENT = (
|
||||||
"Verification Certificate configured, but request is not signed."
|
"Verification Certificate configured, but request is not signed."
|
||||||
)
|
)
|
||||||
|
@ -42,7 +43,7 @@ class AuthNRequest:
|
||||||
|
|
||||||
relay_state: Optional[str] = None
|
relay_state: Optional[str] = None
|
||||||
|
|
||||||
name_id_policy: str = SAML_NAME_ID_FORMAT_EMAIL
|
name_id_policy: str = SAML_NAME_ID_FORMAT_UNSPECIFIED
|
||||||
|
|
||||||
|
|
||||||
class AuthNRequestParser:
|
class AuthNRequestParser:
|
||||||
|
@ -69,16 +70,21 @@ class AuthNRequestParser:
|
||||||
auth_n_request = AuthNRequest(id=root.attrib["ID"], relay_state=relay_state)
|
auth_n_request = AuthNRequest(id=root.attrib["ID"], relay_state=relay_state)
|
||||||
|
|
||||||
# Check if AuthnRequest has a NameID Policy object
|
# Check if AuthnRequest has a NameID Policy object
|
||||||
name_id_policies = root.findall(f"{{{NS_SAML_PROTOCOL}}}:NameIDPolicy")
|
name_id_policies = root.findall(f"{{{NS_SAML_PROTOCOL}}}NameIDPolicy")
|
||||||
if len(name_id_policies) > 0:
|
if len(name_id_policies) > 0:
|
||||||
name_id_policy = name_id_policies[0]
|
name_id_policy = name_id_policies[0]
|
||||||
auth_n_request.name_id_policy = name_id_policy.attrib["Format"]
|
auth_n_request.name_id_policy = name_id_policy.attrib.get(
|
||||||
|
"Format", SAML_NAME_ID_FORMAT_UNSPECIFIED
|
||||||
|
)
|
||||||
|
|
||||||
return auth_n_request
|
return auth_n_request
|
||||||
|
|
||||||
def parse(self, saml_request: str, relay_state: Optional[str]) -> AuthNRequest:
|
def parse(self, saml_request: str, relay_state: Optional[str]) -> AuthNRequest:
|
||||||
"""Validate and parse raw request with enveloped signautre."""
|
"""Validate and parse raw request with enveloped signautre."""
|
||||||
|
try:
|
||||||
decoded_xml = b64decode(saml_request.encode()).decode()
|
decoded_xml = b64decode(saml_request.encode()).decode()
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
raise CannotHandleAssertion(ERROR_CANNOT_DECODE_REQUEST)
|
||||||
|
|
||||||
verifier = self.provider.verification_kp
|
verifier = self.provider.verification_kp
|
||||||
|
|
||||||
|
@ -121,7 +127,10 @@ class AuthNRequestParser:
|
||||||
sig_alg: Optional[str] = None,
|
sig_alg: Optional[str] = None,
|
||||||
) -> AuthNRequest:
|
) -> AuthNRequest:
|
||||||
"""Validate and parse raw request with detached signature"""
|
"""Validate and parse raw request with detached signature"""
|
||||||
|
try:
|
||||||
decoded_xml = decode_base64_and_inflate(saml_request)
|
decoded_xml = decode_base64_and_inflate(saml_request)
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
raise CannotHandleAssertion(ERROR_CANNOT_DECODE_REQUEST)
|
||||||
|
|
||||||
verifier = self.provider.verification_kp
|
verifier = self.provider.verification_kp
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ from authentik.providers.saml.processors.assertion import AssertionProcessor
|
||||||
from authentik.providers.saml.processors.request_parser import AuthNRequestParser
|
from authentik.providers.saml.processors.request_parser import AuthNRequestParser
|
||||||
from authentik.sources.saml.exceptions import MismatchedRequestID
|
from authentik.sources.saml.exceptions import MismatchedRequestID
|
||||||
from authentik.sources.saml.models import SAMLSource
|
from authentik.sources.saml.models import SAMLSource
|
||||||
from authentik.sources.saml.processors.constants import SAML_NAME_ID_FORMAT_EMAIL
|
from authentik.sources.saml.processors.constants import SAML_NAME_ID_FORMAT_UNSPECIFIED
|
||||||
from authentik.sources.saml.processors.request import (
|
from authentik.sources.saml.processors.request import (
|
||||||
SESSION_REQUEST_ID,
|
SESSION_REQUEST_ID,
|
||||||
RequestProcessor,
|
RequestProcessor,
|
||||||
|
@ -206,5 +206,5 @@ class TestAuthNRequest(TestCase):
|
||||||
REDIRECT_REQUEST, REDIRECT_RELAY_STATE, REDIRECT_SIGNATURE, REDIRECT_SIG_ALG
|
REDIRECT_REQUEST, REDIRECT_RELAY_STATE, REDIRECT_SIGNATURE, REDIRECT_SIG_ALG
|
||||||
)
|
)
|
||||||
self.assertEqual(parsed_request.id, "_dcf55fcd27a887e60a7ef9ee6fd3adab")
|
self.assertEqual(parsed_request.id, "_dcf55fcd27a887e60a7ef9ee6fd3adab")
|
||||||
self.assertEqual(parsed_request.name_id_policy, SAML_NAME_ID_FORMAT_EMAIL)
|
self.assertEqual(parsed_request.name_id_policy, SAML_NAME_ID_FORMAT_UNSPECIFIED)
|
||||||
self.assertEqual(parsed_request.relay_state, REDIRECT_RELAY_STATE)
|
self.assertEqual(parsed_request.relay_state, REDIRECT_RELAY_STATE)
|
||||||
|
|
|
@ -17,6 +17,7 @@ from authentik.providers.saml.models import SAMLBindings, SAMLProvider
|
||||||
from authentik.providers.saml.processors.assertion import AssertionProcessor
|
from authentik.providers.saml.processors.assertion import AssertionProcessor
|
||||||
from authentik.providers.saml.processors.request_parser import AuthNRequest
|
from authentik.providers.saml.processors.request_parser import AuthNRequest
|
||||||
from authentik.providers.saml.utils.encoding import deflate_and_base64_encode, nice64
|
from authentik.providers.saml.utils.encoding import deflate_and_base64_encode, nice64
|
||||||
|
from authentik.sources.saml.exceptions import SAMLException
|
||||||
|
|
||||||
LOGGER = get_logger()
|
LOGGER = get_logger()
|
||||||
URL_VALIDATOR = URLValidator(schemes=("http", "https"))
|
URL_VALIDATOR = URLValidator(schemes=("http", "https"))
|
||||||
|
@ -56,22 +57,30 @@ class SAMLFlowFinalView(ChallengeStageView):
|
||||||
provider: SAMLProvider = get_object_or_404(
|
provider: SAMLProvider = get_object_or_404(
|
||||||
SAMLProvider, pk=application.provider_id
|
SAMLProvider, pk=application.provider_id
|
||||||
)
|
)
|
||||||
# Log Application Authorization
|
|
||||||
Event.new(
|
|
||||||
EventAction.AUTHORIZE_APPLICATION,
|
|
||||||
authorized_application=application,
|
|
||||||
flow=self.executor.plan.flow_pk,
|
|
||||||
).from_http(self.request)
|
|
||||||
|
|
||||||
if SESSION_KEY_AUTH_N_REQUEST not in self.request.session:
|
if SESSION_KEY_AUTH_N_REQUEST not in self.request.session:
|
||||||
return self.executor.stage_invalid()
|
return self.executor.stage_invalid()
|
||||||
|
|
||||||
auth_n_request: AuthNRequest = self.request.session.pop(
|
auth_n_request: AuthNRequest = self.request.session.pop(
|
||||||
SESSION_KEY_AUTH_N_REQUEST
|
SESSION_KEY_AUTH_N_REQUEST
|
||||||
)
|
)
|
||||||
|
try:
|
||||||
response = AssertionProcessor(
|
response = AssertionProcessor(
|
||||||
provider, request, auth_n_request
|
provider, request, auth_n_request
|
||||||
).build_response()
|
).build_response()
|
||||||
|
except SAMLException as exc:
|
||||||
|
Event.new(
|
||||||
|
EventAction.CONFIGURATION_ERROR,
|
||||||
|
message=f"Failed to process SAML assertion: {str(exc)}",
|
||||||
|
provider=provider,
|
||||||
|
).from_http(self.request)
|
||||||
|
return self.executor.stage_invalid()
|
||||||
|
|
||||||
|
# Log Application Authorization
|
||||||
|
Event.new(
|
||||||
|
EventAction.AUTHORIZE_APPLICATION,
|
||||||
|
authorized_application=application,
|
||||||
|
flow=self.executor.plan.flow_pk,
|
||||||
|
).from_http(self.request)
|
||||||
|
|
||||||
if provider.sp_binding == SAMLBindings.POST:
|
if provider.sp_binding == SAMLBindings.POST:
|
||||||
form_attrs = {
|
form_attrs = {
|
||||||
|
|
|
@ -44,7 +44,7 @@ class Command(BaseCommand):
|
||||||
user=user,
|
user=user,
|
||||||
intent=TokenIntents.INTENT_RECOVERY,
|
intent=TokenIntents.INTENT_RECOVERY,
|
||||||
description=f"Recovery Token generated by {getuser()} on {_now}",
|
description=f"Recovery Token generated by {getuser()} on {_now}",
|
||||||
identifier=f"ak-recovery-{user}",
|
identifier=f"ak-recovery-{user}-{_now}",
|
||||||
)
|
)
|
||||||
self.stdout.write(
|
self.stdout.write(
|
||||||
(
|
(
|
||||||
|
|
|
@ -15,6 +15,7 @@ import logging
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from json import dumps
|
from json import dumps
|
||||||
|
from tempfile import gettempdir
|
||||||
from time import time
|
from time import time
|
||||||
|
|
||||||
import structlog
|
import structlog
|
||||||
|
@ -193,6 +194,7 @@ CACHES = {
|
||||||
f"redis://:{CONFIG.y('redis.password')}@{CONFIG.y('redis.host')}:6379"
|
f"redis://:{CONFIG.y('redis.password')}@{CONFIG.y('redis.host')}:6379"
|
||||||
f"/{CONFIG.y('redis.cache_db')}"
|
f"/{CONFIG.y('redis.cache_db')}"
|
||||||
),
|
),
|
||||||
|
"TIMEOUT": int(CONFIG.y("redis.cache_timeout", 300)),
|
||||||
"OPTIONS": {"CLIENT_CLASS": "django_redis.client.DefaultClient"},
|
"OPTIONS": {"CLIENT_CLASS": "django_redis.client.DefaultClient"},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -341,7 +343,7 @@ DBBACKUP_FILENAME_TEMPLATE = "authentik-backup-{datetime}.sql"
|
||||||
DBBACKUP_CONNECTOR_MAPPING = {
|
DBBACKUP_CONNECTOR_MAPPING = {
|
||||||
"django_prometheus.db.backends.postgresql": "dbbackup.db.postgresql.PgDumpConnector",
|
"django_prometheus.db.backends.postgresql": "dbbackup.db.postgresql.PgDumpConnector",
|
||||||
}
|
}
|
||||||
|
DBBACKUP_TMP_DIR = gettempdir() if DEBUG else "/tmp" # nosec
|
||||||
if CONFIG.y("postgresql.s3_backup"):
|
if CONFIG.y("postgresql.s3_backup"):
|
||||||
DBBACKUP_STORAGE = "storages.backends.s3boto3.S3Boto3Storage"
|
DBBACKUP_STORAGE = "storages.backends.s3boto3.S3Boto3Storage"
|
||||||
DBBACKUP_STORAGE_OPTIONS = {
|
DBBACKUP_STORAGE_OPTIONS = {
|
||||||
|
|
|
@ -15,6 +15,10 @@ class PytestTestRunner: # pragma: no cover
|
||||||
settings.CELERY_TASK_ALWAYS_EAGER = True
|
settings.CELERY_TASK_ALWAYS_EAGER = True
|
||||||
CONFIG.y_set("authentik.avatars", "none")
|
CONFIG.y_set("authentik.avatars", "none")
|
||||||
CONFIG.y_set("authentik.geoip", "tests/GeoLite2-City-Test.mmdb")
|
CONFIG.y_set("authentik.geoip", "tests/GeoLite2-City-Test.mmdb")
|
||||||
|
CONFIG.y_set(
|
||||||
|
"outposts.docker_image_base",
|
||||||
|
"beryju.org/authentik/outpost-%(type)s:gh-master",
|
||||||
|
)
|
||||||
|
|
||||||
def run_tests(self, test_labels):
|
def run_tests(self, test_labels):
|
||||||
"""Run pytest and return the exitcode.
|
"""Run pytest and return the exitcode.
|
||||||
|
|
|
@ -60,14 +60,21 @@ class LDAPPasswordChanger:
|
||||||
def check_ad_password_complexity_enabled(self) -> bool:
|
def check_ad_password_complexity_enabled(self) -> bool:
|
||||||
"""Check if DOMAIN_PASSWORD_COMPLEX is enabled"""
|
"""Check if DOMAIN_PASSWORD_COMPLEX is enabled"""
|
||||||
root_dn = self.get_domain_root_dn()
|
root_dn = self.get_domain_root_dn()
|
||||||
|
try:
|
||||||
root_attrs = self._source.connection.extend.standard.paged_search(
|
root_attrs = self._source.connection.extend.standard.paged_search(
|
||||||
search_base=root_dn,
|
search_base=root_dn,
|
||||||
search_filter="(objectClass=*)",
|
search_filter="(objectClass=*)",
|
||||||
search_scope=ldap3.BASE,
|
search_scope=ldap3.BASE,
|
||||||
attributes=["pwdProperties"],
|
attributes=["pwdProperties"],
|
||||||
)
|
)
|
||||||
|
except ldap3.core.exceptions.LDAPAttributeError:
|
||||||
|
return False
|
||||||
root_attrs = list(root_attrs)[0]
|
root_attrs = list(root_attrs)[0]
|
||||||
pwd_properties = PwdProperties(root_attrs["attributes"]["pwdProperties"])
|
raw_pwd_properties = root_attrs.get("attributes", {}).get("pwdProperties", None)
|
||||||
|
if raw_pwd_properties is None:
|
||||||
|
return False
|
||||||
|
|
||||||
|
pwd_properties = PwdProperties(raw_pwd_properties)
|
||||||
if PwdProperties.DOMAIN_PASSWORD_COMPLEX in pwd_properties:
|
if PwdProperties.DOMAIN_PASSWORD_COMPLEX in pwd_properties:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
|
@ -2,17 +2,21 @@
|
||||||
from authentik.lib.sentry import SentryIgnoredException
|
from authentik.lib.sentry import SentryIgnoredException
|
||||||
|
|
||||||
|
|
||||||
class MissingSAMLResponse(SentryIgnoredException):
|
class SAMLException(SentryIgnoredException):
|
||||||
|
"""Base SAML Exception"""
|
||||||
|
|
||||||
|
|
||||||
|
class MissingSAMLResponse(SAMLException):
|
||||||
"""Exception raised when request does not contain SAML Response."""
|
"""Exception raised when request does not contain SAML Response."""
|
||||||
|
|
||||||
|
|
||||||
class UnsupportedNameIDFormat(SentryIgnoredException):
|
class UnsupportedNameIDFormat(SAMLException):
|
||||||
"""Exception raised when SAML Response contains NameID Format not supported."""
|
"""Exception raised when SAML Response contains NameID Format not supported."""
|
||||||
|
|
||||||
|
|
||||||
class MismatchedRequestID(SentryIgnoredException):
|
class MismatchedRequestID(SAMLException):
|
||||||
"""Exception raised when the returned request ID doesn't match the saved ID."""
|
"""Exception raised when the returned request ID doesn't match the saved ID."""
|
||||||
|
|
||||||
|
|
||||||
class InvalidSignature(SentryIgnoredException):
|
class InvalidSignature(SAMLException):
|
||||||
"""Signature of XML Object is either missing or invalid"""
|
"""Signature of XML Object is either missing or invalid"""
|
||||||
|
|
|
@ -15,6 +15,9 @@ NS_MAP = {
|
||||||
|
|
||||||
SAML_NAME_ID_FORMAT_EMAIL = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
|
SAML_NAME_ID_FORMAT_EMAIL = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
|
||||||
SAML_NAME_ID_FORMAT_PERSISTENT = "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"
|
SAML_NAME_ID_FORMAT_PERSISTENT = "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"
|
||||||
|
SAML_NAME_ID_FORMAT_UNSPECIFIED = (
|
||||||
|
"urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
|
||||||
|
)
|
||||||
SAML_NAME_ID_FORMAT_X509 = "urn:oasis:names:tc:SAML:2.0:nameid-format:X509SubjectName"
|
SAML_NAME_ID_FORMAT_X509 = "urn:oasis:names:tc:SAML:2.0:nameid-format:X509SubjectName"
|
||||||
SAML_NAME_ID_FORMAT_WINDOWS = (
|
SAML_NAME_ID_FORMAT_WINDOWS = (
|
||||||
"urn:oasis:names:tc:SAML:2.0:nameid-format:WindowsDomainQualifiedName"
|
"urn:oasis:names:tc:SAML:2.0:nameid-format:WindowsDomainQualifiedName"
|
||||||
|
|
|
@ -9,7 +9,7 @@ from rest_framework.permissions import IsAdminUser
|
||||||
from rest_framework.request import Request
|
from rest_framework.request import Request
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.serializers import ModelSerializer
|
from rest_framework.serializers import ModelSerializer
|
||||||
from rest_framework.viewsets import GenericViewSet, ModelViewSet, ReadOnlyModelViewSet
|
from rest_framework.viewsets import GenericViewSet, ModelViewSet
|
||||||
|
|
||||||
from authentik.api.authorization import OwnerFilter, OwnerPermissions
|
from authentik.api.authorization import OwnerFilter, OwnerPermissions
|
||||||
from authentik.core.api.used_by import UsedByMixin
|
from authentik.core.api.used_by import UsedByMixin
|
||||||
|
@ -94,7 +94,7 @@ class DuoDeviceViewSet(
|
||||||
filter_backends = [OwnerFilter, DjangoFilterBackend, OrderingFilter, SearchFilter]
|
filter_backends = [OwnerFilter, DjangoFilterBackend, OrderingFilter, SearchFilter]
|
||||||
|
|
||||||
|
|
||||||
class DuoAdminDeviceViewSet(ReadOnlyModelViewSet):
|
class DuoAdminDeviceViewSet(ModelViewSet):
|
||||||
"""Viewset for Duo authenticator devices (for admins)"""
|
"""Viewset for Duo authenticator devices (for admins)"""
|
||||||
|
|
||||||
permission_classes = [IsAdminUser]
|
permission_classes = [IsAdminUser]
|
||||||
|
|
|
@ -3,6 +3,7 @@ from django.http import HttpRequest, HttpResponse
|
||||||
from rest_framework.fields import CharField
|
from rest_framework.fields import CharField
|
||||||
from structlog.stdlib import get_logger
|
from structlog.stdlib import get_logger
|
||||||
|
|
||||||
|
from authentik.events.models import Event, EventAction
|
||||||
from authentik.flows.challenge import (
|
from authentik.flows.challenge import (
|
||||||
Challenge,
|
Challenge,
|
||||||
ChallengeResponse,
|
ChallengeResponse,
|
||||||
|
@ -11,6 +12,7 @@ from authentik.flows.challenge import (
|
||||||
)
|
)
|
||||||
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER
|
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER
|
||||||
from authentik.flows.stage import ChallengeStageView
|
from authentik.flows.stage import ChallengeStageView
|
||||||
|
from authentik.flows.views import InvalidStageError
|
||||||
from authentik.stages.authenticator_duo.models import AuthenticatorDuoStage, DuoDevice
|
from authentik.stages.authenticator_duo.models import AuthenticatorDuoStage, DuoDevice
|
||||||
|
|
||||||
LOGGER = get_logger()
|
LOGGER = get_logger()
|
||||||
|
@ -42,7 +44,15 @@ class AuthenticatorDuoStageView(ChallengeStageView):
|
||||||
def get_challenge(self, *args, **kwargs) -> Challenge:
|
def get_challenge(self, *args, **kwargs) -> Challenge:
|
||||||
user = self.get_pending_user()
|
user = self.get_pending_user()
|
||||||
stage: AuthenticatorDuoStage = self.executor.current_stage
|
stage: AuthenticatorDuoStage = self.executor.current_stage
|
||||||
|
try:
|
||||||
enroll = stage.client.enroll(user.username)
|
enroll = stage.client.enroll(user.username)
|
||||||
|
except RuntimeError as exc:
|
||||||
|
Event.new(
|
||||||
|
EventAction.CONFIGURATION_ERROR,
|
||||||
|
message=f"Failed to enroll user: {str(exc)}",
|
||||||
|
user=user,
|
||||||
|
).from_http(self.request, user)
|
||||||
|
raise InvalidStageError(str(exc)) from exc
|
||||||
user_id = enroll["user_id"]
|
user_id = enroll["user_id"]
|
||||||
self.request.session[SESSION_KEY_DUO_USER_ID] = user_id
|
self.request.session[SESSION_KEY_DUO_USER_ID] = user_id
|
||||||
self.request.session[SESSION_KEY_DUO_ACTIVATION_CODE] = enroll[
|
self.request.session[SESSION_KEY_DUO_ACTIVATION_CODE] = enroll[
|
||||||
|
|
|
@ -10,7 +10,7 @@ from authentik.flows.challenge import (
|
||||||
ChallengeTypes,
|
ChallengeTypes,
|
||||||
WithUserInfoChallenge,
|
WithUserInfoChallenge,
|
||||||
)
|
)
|
||||||
from authentik.flows.models import NotConfiguredAction
|
from authentik.flows.models import NotConfiguredAction, Stage
|
||||||
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER
|
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER
|
||||||
from authentik.flows.stage import ChallengeStageView
|
from authentik.flows.stage import ChallengeStageView
|
||||||
from authentik.stages.authenticator_validate.challenge import (
|
from authentik.stages.authenticator_validate.challenge import (
|
||||||
|
@ -143,9 +143,12 @@ class AuthenticatorValidateStageView(ChallengeStageView):
|
||||||
return self.executor.stage_invalid()
|
return self.executor.stage_invalid()
|
||||||
if stage.not_configured_action == NotConfiguredAction.CONFIGURE:
|
if stage.not_configured_action == NotConfiguredAction.CONFIGURE:
|
||||||
LOGGER.debug("Authenticator not configured, sending user to configure")
|
LOGGER.debug("Authenticator not configured, sending user to configure")
|
||||||
|
# Because the foreign key to stage.configuration_stage points to
|
||||||
|
# a base stage class, we need to do another lookup
|
||||||
|
stage = Stage.objects.get_subclass(pk=stage.configuration_stage.pk)
|
||||||
# plan.insert inserts at 1 index, so when stage_ok pops 0,
|
# plan.insert inserts at 1 index, so when stage_ok pops 0,
|
||||||
# the configuration stage is next
|
# the configuration stage is next
|
||||||
self.executor.plan.insert(stage.configuration_stage)
|
self.executor.plan.insert(stage)
|
||||||
return self.executor.stage_ok()
|
return self.executor.stage_ok()
|
||||||
return super().get(request, *args, **kwargs)
|
return super().get(request, *args, **kwargs)
|
||||||
|
|
||||||
|
|
|
@ -4,11 +4,14 @@ from unittest.mock import MagicMock, patch
|
||||||
from django.contrib.sessions.middleware import SessionMiddleware
|
from django.contrib.sessions.middleware import SessionMiddleware
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.test.client import RequestFactory
|
from django.test.client import RequestFactory
|
||||||
|
from django.urls.base import reverse
|
||||||
|
from django.utils.encoding import force_str
|
||||||
from django_otp.plugins.otp_totp.models import TOTPDevice
|
from django_otp.plugins.otp_totp.models import TOTPDevice
|
||||||
from rest_framework.exceptions import ValidationError
|
from rest_framework.exceptions import ValidationError
|
||||||
|
|
||||||
from authentik.core.models import User
|
from authentik.core.models import User
|
||||||
from authentik.flows.models import NotConfiguredAction
|
from authentik.flows.challenge import ChallengeTypes
|
||||||
|
from authentik.flows.models import Flow, FlowStageBinding, NotConfiguredAction
|
||||||
from authentik.flows.tests.test_planner import dummy_get_response
|
from authentik.flows.tests.test_planner import dummy_get_response
|
||||||
from authentik.providers.oauth2.generators import (
|
from authentik.providers.oauth2.generators import (
|
||||||
generate_client_id,
|
generate_client_id,
|
||||||
|
@ -24,7 +27,9 @@ from authentik.stages.authenticator_validate.challenge import (
|
||||||
validate_challenge_duo,
|
validate_challenge_duo,
|
||||||
validate_challenge_webauthn,
|
validate_challenge_webauthn,
|
||||||
)
|
)
|
||||||
|
from authentik.stages.authenticator_validate.models import AuthenticatorValidateStage
|
||||||
from authentik.stages.authenticator_webauthn.models import WebAuthnDevice
|
from authentik.stages.authenticator_webauthn.models import WebAuthnDevice
|
||||||
|
from authentik.stages.identification.models import IdentificationStage, UserFields
|
||||||
|
|
||||||
|
|
||||||
class AuthenticatorValidateStageTests(TestCase):
|
class AuthenticatorValidateStageTests(TestCase):
|
||||||
|
@ -34,6 +39,50 @@ class AuthenticatorValidateStageTests(TestCase):
|
||||||
self.user = User.objects.get(username="akadmin")
|
self.user = User.objects.get(username="akadmin")
|
||||||
self.request_factory = RequestFactory()
|
self.request_factory = RequestFactory()
|
||||||
|
|
||||||
|
def test_not_configured_action(self):
|
||||||
|
"""Test not_configured_action"""
|
||||||
|
conf_stage = IdentificationStage.objects.create(
|
||||||
|
name="conf",
|
||||||
|
user_fields=[
|
||||||
|
UserFields.USERNAME,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
stage = AuthenticatorValidateStage.objects.create(
|
||||||
|
name="foo",
|
||||||
|
not_configured_action=NotConfiguredAction.CONFIGURE,
|
||||||
|
configuration_stage=conf_stage,
|
||||||
|
)
|
||||||
|
flow = Flow.objects.create(name="test", slug="test", title="test")
|
||||||
|
FlowStageBinding.objects.create(target=flow, stage=conf_stage, order=0)
|
||||||
|
FlowStageBinding.objects.create(target=flow, stage=stage, order=1)
|
||||||
|
|
||||||
|
response = self.client.post(
|
||||||
|
reverse("authentik_api:flow-executor", kwargs={"flow_slug": flow.slug}),
|
||||||
|
{"uid_field": "akadmin"},
|
||||||
|
)
|
||||||
|
self.assertEqual(response.status_code, 302)
|
||||||
|
response = self.client.get(
|
||||||
|
reverse("authentik_api:flow-executor", kwargs={"flow_slug": flow.slug}),
|
||||||
|
follow=True,
|
||||||
|
)
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertJSONEqual(
|
||||||
|
force_str(response.content),
|
||||||
|
{
|
||||||
|
"type": ChallengeTypes.NATIVE.value,
|
||||||
|
"component": "ak-stage-identification",
|
||||||
|
"password_fields": False,
|
||||||
|
"primary_action": "Log in",
|
||||||
|
"flow_info": {
|
||||||
|
"background": flow.background_url,
|
||||||
|
"cancel_url": reverse("authentik_flows:cancel"),
|
||||||
|
"title": flow.title,
|
||||||
|
},
|
||||||
|
"user_fields": ["username"],
|
||||||
|
"sources": [],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
def test_stage_validation(self):
|
def test_stage_validation(self):
|
||||||
"""Test serializer validation"""
|
"""Test serializer validation"""
|
||||||
self.client.force_login(self.user)
|
self.client.force_login(self.user)
|
||||||
|
|
|
@ -51,7 +51,7 @@ class CurrentTenantSerializer(PassiveSerializer):
|
||||||
ui_footer_links = ListField(
|
ui_footer_links = ListField(
|
||||||
child=FooterLinkSerializer(),
|
child=FooterLinkSerializer(),
|
||||||
read_only=True,
|
read_only=True,
|
||||||
default=CONFIG.y("authentik.footer_links"),
|
default=CONFIG.y("footer_links", []),
|
||||||
)
|
)
|
||||||
|
|
||||||
flow_unenrollment = CharField(source="flow_unenrollment.slug", required=False)
|
flow_unenrollment = CharField(source="flow_unenrollment.slug", required=False)
|
||||||
|
|
|
@ -19,7 +19,26 @@ class TestTenants(TestCase):
|
||||||
"branding_favicon": "/static/dist/assets/icons/icon.png",
|
"branding_favicon": "/static/dist/assets/icons/icon.png",
|
||||||
"branding_title": "authentik",
|
"branding_title": "authentik",
|
||||||
"matched_domain": "authentik-default",
|
"matched_domain": "authentik-default",
|
||||||
"ui_footer_links": CONFIG.y("authentik.footer_links"),
|
"ui_footer_links": CONFIG.y("footer_links"),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_tenant_subdomain(self):
|
||||||
|
"""Test Current tenant API"""
|
||||||
|
Tenant.objects.all().delete()
|
||||||
|
Tenant.objects.create(domain="bar.baz", branding_title="custom")
|
||||||
|
self.assertJSONEqual(
|
||||||
|
force_str(
|
||||||
|
self.client.get(
|
||||||
|
reverse("authentik_api:tenant-current"), HTTP_HOST="foo.bar.baz"
|
||||||
|
).content
|
||||||
|
),
|
||||||
|
{
|
||||||
|
"branding_logo": "/static/dist/assets/icons/icon_left_brand.svg",
|
||||||
|
"branding_favicon": "/static/dist/assets/icons/icon.png",
|
||||||
|
"branding_title": "custom",
|
||||||
|
"matched_domain": "bar.baz",
|
||||||
|
"ui_footer_links": CONFIG.y("footer_links"),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -33,6 +52,6 @@ class TestTenants(TestCase):
|
||||||
"branding_favicon": "/static/dist/assets/icons/icon.png",
|
"branding_favicon": "/static/dist/assets/icons/icon.png",
|
||||||
"branding_title": "authentik",
|
"branding_title": "authentik",
|
||||||
"matched_domain": "fallback",
|
"matched_domain": "fallback",
|
||||||
"ui_footer_links": CONFIG.y("authentik.footer_links"),
|
"ui_footer_links": CONFIG.y("footer_links"),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
"""Tenant utilities"""
|
"""Tenant utilities"""
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from django.db.models import Q
|
from django.db.models import F, Q
|
||||||
|
from django.db.models import Value as V
|
||||||
from django.http.request import HttpRequest
|
from django.http.request import HttpRequest
|
||||||
|
|
||||||
from authentik import __version__
|
from authentik import __version__
|
||||||
|
@ -14,8 +15,10 @@ DEFAULT_TENANT = Tenant(domain="fallback")
|
||||||
|
|
||||||
def get_tenant_for_request(request: HttpRequest) -> Tenant:
|
def get_tenant_for_request(request: HttpRequest) -> Tenant:
|
||||||
"""Get tenant object for current request"""
|
"""Get tenant object for current request"""
|
||||||
db_tenants = Tenant.objects.filter(
|
db_tenants = (
|
||||||
Q(domain__iendswith=request.get_host()) | _q_default
|
Tenant.objects.annotate(host_domain=V(request.get_host()))
|
||||||
|
.filter(Q(host_domain__iendswith=F("domain")) | _q_default)
|
||||||
|
.order_by("default")
|
||||||
)
|
)
|
||||||
if not db_tenants.exists():
|
if not db_tenants.exists():
|
||||||
return DEFAULT_TENANT
|
return DEFAULT_TENANT
|
||||||
|
@ -28,5 +31,5 @@ def context_processor(request: HttpRequest) -> dict[str, Any]:
|
||||||
return {
|
return {
|
||||||
"tenant": tenant,
|
"tenant": tenant,
|
||||||
"ak_version": __version__,
|
"ak_version": __version__,
|
||||||
"footer_links": CONFIG.y("authentik.footer_links"),
|
"footer_links": CONFIG.y("footer_links"),
|
||||||
}
|
}
|
||||||
|
|
|
@ -148,7 +148,7 @@ stages:
|
||||||
inputs:
|
inputs:
|
||||||
script: |
|
script: |
|
||||||
pipenv run python -m scripts.generate_ci_config
|
pipenv run python -m scripts.generate_ci_config
|
||||||
pipenv run ./manage.py migrate
|
pipenv run python -m lifecycle.migrate
|
||||||
- job: migrations_from_previous_release
|
- job: migrations_from_previous_release
|
||||||
pool:
|
pool:
|
||||||
vmImage: 'ubuntu-latest'
|
vmImage: 'ubuntu-latest'
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/getsentry/sentry-go"
|
"github.com/getsentry/sentry-go"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
@ -10,6 +13,8 @@ import (
|
||||||
"goauthentik.io/internal/config"
|
"goauthentik.io/internal/config"
|
||||||
"goauthentik.io/internal/constants"
|
"goauthentik.io/internal/constants"
|
||||||
"goauthentik.io/internal/gounicorn"
|
"goauthentik.io/internal/gounicorn"
|
||||||
|
"goauthentik.io/internal/outpost/ak"
|
||||||
|
"goauthentik.io/internal/outpost/proxy"
|
||||||
"goauthentik.io/internal/web"
|
"goauthentik.io/internal/web"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -30,23 +35,53 @@ func main() {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ex := common.Init()
|
||||||
defer common.Defer()
|
defer common.Defer()
|
||||||
|
|
||||||
rl := log.WithField("logger", "authentik.g")
|
u, _ := url.Parse("http://localhost:8000")
|
||||||
wg := sync.WaitGroup{}
|
|
||||||
wg.Add(3)
|
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
g := gounicorn.NewGoUnicorn()
|
|
||||||
for {
|
for {
|
||||||
err := g.Start()
|
g := gounicorn.NewGoUnicorn()
|
||||||
rl.WithError(err).Warning("gunicorn process died, restarting")
|
go attemptStartBackend(g)
|
||||||
}
|
|
||||||
}()
|
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
ws := web.NewWebServer()
|
ws := web.NewWebServer()
|
||||||
ws.Run()
|
ws.Run()
|
||||||
}()
|
|
||||||
wg.Wait()
|
proxy :=
|
||||||
|
|
||||||
|
<-ex
|
||||||
|
ws.Stop()
|
||||||
|
g.Kill()
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
|
||||||
|
maxTries := 100
|
||||||
|
attempt := 0
|
||||||
|
for {
|
||||||
|
err := attemptProxyStart(u, ex)
|
||||||
|
if err != nil {
|
||||||
|
attempt += 1
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
if attempt > maxTries {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func attemptStartBackend(g *gounicorn.GoUnicorn) error {
|
||||||
|
for {
|
||||||
|
err := g.Start()
|
||||||
|
log.WithField("logger", "authentik.g").WithError(err).Warning("gunicorn process died, restarting")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func attemptProxyStart(u *url.URL, exitSignal chan os.Signal) (*ak.APIController, error) {
|
||||||
|
ac := ak.NewAPIController(*u, config.G.SecretKey)
|
||||||
|
if ac == nil {
|
||||||
|
return nil, errors.New("failed to start")
|
||||||
|
}
|
||||||
|
ac.Server = proxy.NewServer(ac)
|
||||||
|
return ac, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ services:
|
||||||
networks:
|
networks:
|
||||||
- internal
|
- internal
|
||||||
server:
|
server:
|
||||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2021.6.1-rc6}
|
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2021.6.2}
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
command: server
|
command: server
|
||||||
environment:
|
environment:
|
||||||
|
@ -38,21 +38,13 @@ services:
|
||||||
- geoip:/geoip
|
- geoip:/geoip
|
||||||
networks:
|
networks:
|
||||||
- internal
|
- internal
|
||||||
labels:
|
|
||||||
traefik.enable: 'true'
|
|
||||||
traefik.docker.network: internal
|
|
||||||
traefik.http.routers.app-router.rule: PathPrefix(`/`)
|
|
||||||
traefik.http.routers.app-router.service: app-service
|
|
||||||
traefik.http.routers.app-router.tls: 'true'
|
|
||||||
traefik.http.services.app-service.loadbalancer.healthcheck.path: /-/health/live/
|
|
||||||
traefik.http.services.app-service.loadbalancer.server.port: '9000'
|
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
ports:
|
ports:
|
||||||
- "0.0.0.0:9000:9000"
|
- "0.0.0.0:9000:9000"
|
||||||
- "0.0.0.0:9443:9443"
|
- "0.0.0.0:9443:9443"
|
||||||
worker:
|
worker:
|
||||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2021.6.1-rc6}
|
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2021.6.2}
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
command: worker
|
command: worker
|
||||||
networks:
|
networks:
|
||||||
|
|
|
@ -18,6 +18,7 @@ func DefaultConfig() {
|
||||||
Web: WebConfig{
|
Web: WebConfig{
|
||||||
Listen: "localhost:9000",
|
Listen: "localhost:9000",
|
||||||
ListenTLS: "localhost:9443",
|
ListenTLS: "localhost:9443",
|
||||||
|
LoadLocalFiles: false,
|
||||||
},
|
},
|
||||||
Paths: PathsConfig{
|
Paths: PathsConfig{
|
||||||
Media: "./media",
|
Media: "./media",
|
||||||
|
|
|
@ -2,6 +2,7 @@ package config
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Debug bool `yaml:"debug"`
|
Debug bool `yaml:"debug"`
|
||||||
|
SecretKey string `yaml:"secret_key"`
|
||||||
Web WebConfig `yaml:"web"`
|
Web WebConfig `yaml:"web"`
|
||||||
Paths PathsConfig `yaml:"paths"`
|
Paths PathsConfig `yaml:"paths"`
|
||||||
LogLevel string `yaml:"log_level"`
|
LogLevel string `yaml:"log_level"`
|
||||||
|
@ -11,6 +12,7 @@ type Config struct {
|
||||||
type WebConfig struct {
|
type WebConfig struct {
|
||||||
Listen string `yaml:"listen"`
|
Listen string `yaml:"listen"`
|
||||||
ListenTLS string `yaml:"listen_tls"`
|
ListenTLS string `yaml:"listen_tls"`
|
||||||
|
LoadLocalFiles bool `yaml:"load_local_files"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type PathsConfig struct {
|
type PathsConfig struct {
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
const VERSION = "2021.6.1-rc6"
|
const VERSION = "2021.6.2"
|
||||||
|
|
||||||
func BUILD() string {
|
func BUILD() string {
|
||||||
build := os.Getenv("GIT_BUILD_HASH")
|
build := os.Getenv("GIT_BUILD_HASH")
|
||||||
|
|
|
@ -10,27 +10,34 @@ import (
|
||||||
|
|
||||||
type GoUnicorn struct {
|
type GoUnicorn struct {
|
||||||
log *log.Entry
|
log *log.Entry
|
||||||
|
p *exec.Cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGoUnicorn() *GoUnicorn {
|
func NewGoUnicorn() *GoUnicorn {
|
||||||
return &GoUnicorn{
|
logger := log.WithField("logger", "authentik.g.unicorn")
|
||||||
log: log.WithField("logger", "authentik.g.unicorn"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *GoUnicorn) Start() error {
|
|
||||||
command := "gunicorn"
|
command := "gunicorn"
|
||||||
args := []string{"-c", "./lifecycle/gunicorn.conf.py", "authentik.root.asgi:application"}
|
args := []string{"-c", "./lifecycle/gunicorn.conf.py", "authentik.root.asgi:application"}
|
||||||
if config.G.Debug {
|
if config.G.Debug {
|
||||||
command = "python"
|
command = "python"
|
||||||
args = []string{"manage.py", "runserver", "localhost:8000"}
|
args = []string{"manage.py", "runserver", "localhost:8000"}
|
||||||
}
|
}
|
||||||
g.log.WithField("args", args).WithField("cmd", command).Debug("Starting gunicorn")
|
logger.WithField("args", args).WithField("cmd", command).Debug("Starting gunicorn")
|
||||||
p := exec.Command(command, args...)
|
p := exec.Command(command, args...)
|
||||||
p.Env = append(os.Environ(),
|
p.Env = append(os.Environ(),
|
||||||
"WORKERS=2",
|
"WORKERS=2",
|
||||||
)
|
)
|
||||||
p.Stdout = os.Stdout
|
p.Stdout = os.Stdout
|
||||||
p.Stderr = os.Stderr
|
p.Stderr = os.Stderr
|
||||||
return p.Run()
|
return &GoUnicorn{
|
||||||
|
log: logger,
|
||||||
|
p: p,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *GoUnicorn) Start() error {
|
||||||
|
return g.p.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *GoUnicorn) Kill() error {
|
||||||
|
return g.p.Process.Kill()
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ import (
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-openapi/strfmt"
|
"github.com/go-openapi/strfmt"
|
||||||
|
@ -59,7 +58,7 @@ func NewAPIController(akURL url.URL, token string) *APIController {
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithError(err).Error("Failed to fetch configuration")
|
log.WithError(err).Error("Failed to fetch configuration")
|
||||||
os.Exit(1)
|
return nil
|
||||||
}
|
}
|
||||||
outpost := outposts.Results[0]
|
outpost := outposts.Results[0]
|
||||||
doGlobalSetup(outpost.Config)
|
doGlobalSetup(outpost.Config)
|
||||||
|
|
|
@ -446,15 +446,17 @@ func (p *OAuthProxy) addHeadersForProxying(rw http.ResponseWriter, req *http.Req
|
||||||
username = session.Email
|
username = session.Email
|
||||||
}
|
}
|
||||||
authVal := b64.StdEncoding.EncodeToString([]byte(username + ":" + password))
|
authVal := b64.StdEncoding.EncodeToString([]byte(username + ":" + password))
|
||||||
|
p.logger.WithField("username", username).Trace("setting http basic auth")
|
||||||
req.Header["Authorization"] = []string{fmt.Sprintf("Basic %s", authVal)}
|
req.Header["Authorization"] = []string{fmt.Sprintf("Basic %s", authVal)}
|
||||||
}
|
}
|
||||||
// Check if user has additional headers set that we should sent
|
// Check if user has additional headers set that we should sent
|
||||||
if additionalHeaders, ok := userAttributes["additionalHeaders"].(map[string]string); ok {
|
if additionalHeaders, ok := userAttributes["additionalHeaders"].(map[string]interface{}); ok {
|
||||||
|
p.logger.WithField("headers", additionalHeaders).Trace("setting additional headers")
|
||||||
if additionalHeaders == nil {
|
if additionalHeaders == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for key, value := range additionalHeaders {
|
for key, value := range additionalHeaders {
|
||||||
req.Header.Set(key, value)
|
req.Header.Set(key, toString(value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package proxy
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
var xForwardedHost = http.CanonicalHeaderKey("X-Forwarded-Host")
|
var xForwardedHost = http.CanonicalHeaderKey("X-Forwarded-Host")
|
||||||
|
@ -18,3 +19,16 @@ func getHost(req *http.Request) string {
|
||||||
}
|
}
|
||||||
return hostOnly
|
return hostOnly
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// toString Generic to string function, currently supports actual strings and integers
|
||||||
|
func toString(in interface{}) string {
|
||||||
|
switch v := in.(type) {
|
||||||
|
case string:
|
||||||
|
return v
|
||||||
|
case *string:
|
||||||
|
return *v
|
||||||
|
case int:
|
||||||
|
return strconv.Itoa(v)
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/gorilla/handlers"
|
"github.com/gorilla/handlers"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
@ -49,17 +48,12 @@ func NewWebServer() *WebServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ws *WebServer) Run() {
|
func (ws *WebServer) Run() {
|
||||||
wg := sync.WaitGroup{}
|
|
||||||
wg.Add(2)
|
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
ws.listenPlain()
|
ws.listenPlain()
|
||||||
}()
|
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
ws.listenTLS()
|
ws.listenTLS()
|
||||||
}()
|
}
|
||||||
wg.Done()
|
|
||||||
|
func (ws *WebServer) Stop() {
|
||||||
|
ws.stop <- struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ws *WebServer) listenPlain() {
|
func (ws *WebServer) listenPlain() {
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
|
|
||||||
func (ws *WebServer) configureStatic() {
|
func (ws *WebServer) configureStatic() {
|
||||||
statRouter := ws.lh.NewRoute().Subrouter()
|
statRouter := ws.lh.NewRoute().Subrouter()
|
||||||
if config.G.Debug {
|
if config.G.Debug || config.G.Web.LoadLocalFiles {
|
||||||
ws.log.Debug("Using local static files")
|
ws.log.Debug("Using local static files")
|
||||||
ws.lh.PathPrefix("/static/dist").Handler(http.StripPrefix("/static/dist", http.FileServer(http.Dir("./web/dist"))))
|
ws.lh.PathPrefix("/static/dist").Handler(http.StripPrefix("/static/dist", http.FileServer(http.Dir("./web/dist"))))
|
||||||
ws.lh.PathPrefix("/static/authentik").Handler(http.StripPrefix("/static/authentik", http.FileServer(http.Dir("./web/authentik"))))
|
ws.lh.PathPrefix("/static/authentik").Handler(http.StripPrefix("/static/authentik", http.FileServer(http.Dir("./web/authentik"))))
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
all: clean
|
all: clean
|
||||||
|
|
||||||
run:
|
|
||||||
go run -v .
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
go mod tidy
|
go mod tidy
|
||||||
go clean .
|
go clean .
|
||||||
|
|
||||||
|
|
130
schema.yml
|
@ -1,7 +1,7 @@
|
||||||
openapi: 3.0.3
|
openapi: 3.0.3
|
||||||
info:
|
info:
|
||||||
title: authentik
|
title: authentik
|
||||||
version: 2021.6.1-rc5
|
version: 2021.6.2
|
||||||
description: Making authentication simple.
|
description: Making authentication simple.
|
||||||
contact:
|
contact:
|
||||||
email: hello@beryju.org
|
email: hello@beryju.org
|
||||||
|
@ -236,6 +236,37 @@ paths:
|
||||||
$ref: '#/components/schemas/ValidationError'
|
$ref: '#/components/schemas/ValidationError'
|
||||||
'403':
|
'403':
|
||||||
$ref: '#/components/schemas/GenericError'
|
$ref: '#/components/schemas/GenericError'
|
||||||
|
post:
|
||||||
|
operationId: authenticators_admin_duo_create
|
||||||
|
description: Viewset for Duo authenticator devices (for admins)
|
||||||
|
tags:
|
||||||
|
- authenticators
|
||||||
|
requestBody:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/DuoDeviceRequest'
|
||||||
|
application/x-www-form-urlencoded:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/DuoDeviceRequest'
|
||||||
|
multipart/form-data:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/DuoDeviceRequest'
|
||||||
|
required: true
|
||||||
|
security:
|
||||||
|
- authentik: []
|
||||||
|
- cookieAuth: []
|
||||||
|
responses:
|
||||||
|
'201':
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/DuoDevice'
|
||||||
|
description: ''
|
||||||
|
'400':
|
||||||
|
$ref: '#/components/schemas/ValidationError'
|
||||||
|
'403':
|
||||||
|
$ref: '#/components/schemas/GenericError'
|
||||||
/api/v2beta/authenticators/admin/duo/{id}/:
|
/api/v2beta/authenticators/admin/duo/{id}/:
|
||||||
get:
|
get:
|
||||||
operationId: authenticators_admin_duo_retrieve
|
operationId: authenticators_admin_duo_retrieve
|
||||||
|
@ -263,6 +294,103 @@ paths:
|
||||||
$ref: '#/components/schemas/ValidationError'
|
$ref: '#/components/schemas/ValidationError'
|
||||||
'403':
|
'403':
|
||||||
$ref: '#/components/schemas/GenericError'
|
$ref: '#/components/schemas/GenericError'
|
||||||
|
put:
|
||||||
|
operationId: authenticators_admin_duo_update
|
||||||
|
description: Viewset for Duo authenticator devices (for admins)
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: id
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
description: A unique integer value identifying this Duo Device.
|
||||||
|
required: true
|
||||||
|
tags:
|
||||||
|
- authenticators
|
||||||
|
requestBody:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/DuoDeviceRequest'
|
||||||
|
application/x-www-form-urlencoded:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/DuoDeviceRequest'
|
||||||
|
multipart/form-data:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/DuoDeviceRequest'
|
||||||
|
required: true
|
||||||
|
security:
|
||||||
|
- authentik: []
|
||||||
|
- cookieAuth: []
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/DuoDevice'
|
||||||
|
description: ''
|
||||||
|
'400':
|
||||||
|
$ref: '#/components/schemas/ValidationError'
|
||||||
|
'403':
|
||||||
|
$ref: '#/components/schemas/GenericError'
|
||||||
|
patch:
|
||||||
|
operationId: authenticators_admin_duo_partial_update
|
||||||
|
description: Viewset for Duo authenticator devices (for admins)
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: id
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
description: A unique integer value identifying this Duo Device.
|
||||||
|
required: true
|
||||||
|
tags:
|
||||||
|
- authenticators
|
||||||
|
requestBody:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/PatchedDuoDeviceRequest'
|
||||||
|
application/x-www-form-urlencoded:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/PatchedDuoDeviceRequest'
|
||||||
|
multipart/form-data:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/PatchedDuoDeviceRequest'
|
||||||
|
security:
|
||||||
|
- authentik: []
|
||||||
|
- cookieAuth: []
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/DuoDevice'
|
||||||
|
description: ''
|
||||||
|
'400':
|
||||||
|
$ref: '#/components/schemas/ValidationError'
|
||||||
|
'403':
|
||||||
|
$ref: '#/components/schemas/GenericError'
|
||||||
|
delete:
|
||||||
|
operationId: authenticators_admin_duo_destroy
|
||||||
|
description: Viewset for Duo authenticator devices (for admins)
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: id
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
description: A unique integer value identifying this Duo Device.
|
||||||
|
required: true
|
||||||
|
tags:
|
||||||
|
- authenticators
|
||||||
|
security:
|
||||||
|
- authentik: []
|
||||||
|
- cookieAuth: []
|
||||||
|
responses:
|
||||||
|
'204':
|
||||||
|
description: No response body
|
||||||
|
'400':
|
||||||
|
$ref: '#/components/schemas/ValidationError'
|
||||||
|
'403':
|
||||||
|
$ref: '#/components/schemas/GenericError'
|
||||||
/api/v2beta/authenticators/admin/static/:
|
/api/v2beta/authenticators/admin/static/:
|
||||||
get:
|
get:
|
||||||
operationId: authenticators_admin_static_list
|
operationId: authenticators_admin_static_list
|
||||||
|
|
|
@ -21,7 +21,13 @@ from authentik.outposts.models import (
|
||||||
)
|
)
|
||||||
from authentik.outposts.tasks import outpost_local_connection
|
from authentik.outposts.tasks import outpost_local_connection
|
||||||
from authentik.providers.proxy.models import ProxyProvider
|
from authentik.providers.proxy.models import ProxyProvider
|
||||||
from tests.e2e.utils import SeleniumTestCase, apply_migration, object_manager, retry
|
from tests.e2e.utils import (
|
||||||
|
USER,
|
||||||
|
SeleniumTestCase,
|
||||||
|
apply_migration,
|
||||||
|
object_manager,
|
||||||
|
retry,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@skipUnless(platform.startswith("linux"), "requires local docker")
|
@skipUnless(platform.startswith("linux"), "requires local docker")
|
||||||
|
@ -47,7 +53,7 @@ class TestProviderProxy(SeleniumTestCase):
|
||||||
"""Start proxy container based on outpost created"""
|
"""Start proxy container based on outpost created"""
|
||||||
client: DockerClient = from_env()
|
client: DockerClient = from_env()
|
||||||
container = client.containers.run(
|
container = client.containers.run(
|
||||||
image=f"ghcr.io/goauthentik/proxy:{__version__}",
|
image="beryju.org/authentik/outpost-proxy:gh-master",
|
||||||
detach=True,
|
detach=True,
|
||||||
network_mode="host",
|
network_mode="host",
|
||||||
auto_remove=True,
|
auto_remove=True,
|
||||||
|
@ -67,6 +73,11 @@ class TestProviderProxy(SeleniumTestCase):
|
||||||
@object_manager
|
@object_manager
|
||||||
def test_proxy_simple(self):
|
def test_proxy_simple(self):
|
||||||
"""Test simple outpost setup with single provider"""
|
"""Test simple outpost setup with single provider"""
|
||||||
|
# set additionalHeaders to test later
|
||||||
|
user = USER()
|
||||||
|
user.attributes["additionalHeaders"] = {"X-Foo": "bar"}
|
||||||
|
user.save()
|
||||||
|
|
||||||
proxy: ProxyProvider = ProxyProvider.objects.create(
|
proxy: ProxyProvider = ProxyProvider.objects.create(
|
||||||
name="proxy_provider",
|
name="proxy_provider",
|
||||||
authorization_flow=Flow.objects.get(
|
authorization_flow=Flow.objects.get(
|
||||||
|
@ -106,6 +117,7 @@ class TestProviderProxy(SeleniumTestCase):
|
||||||
|
|
||||||
full_body_text = self.driver.find_element(By.CSS_SELECTOR, "pre").text
|
full_body_text = self.driver.find_element(By.CSS_SELECTOR, "pre").text
|
||||||
self.assertIn("X-Forwarded-Preferred-Username: akadmin", full_body_text)
|
self.assertIn("X-Forwarded-Preferred-Username: akadmin", full_body_text)
|
||||||
|
self.assertIn("X-Foo: bar", full_body_text)
|
||||||
|
|
||||||
|
|
||||||
@skipUnless(platform.startswith("linux"), "requires local docker")
|
@skipUnless(platform.startswith("linux"), "requires local docker")
|
||||||
|
|
|
@ -104,5 +104,5 @@ class OutpostDockerTests(TestCase):
|
||||||
self.assertEqual(compose["version"], "3.5")
|
self.assertEqual(compose["version"], "3.5")
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
compose["services"]["authentik_proxy"]["image"],
|
compose["services"]["authentik_proxy"]["image"],
|
||||||
f"ghcr.io/goauthentik/proxy:{__version__}",
|
"beryju.org/authentik/outpost-proxy:gh-master",
|
||||||
)
|
)
|
||||||
|
|
|
@ -104,5 +104,5 @@ class TestProxyDocker(TestCase):
|
||||||
self.assertEqual(compose["version"], "3.5")
|
self.assertEqual(compose["version"], "3.5")
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
compose["services"]["authentik_proxy"]["image"],
|
compose["services"]["authentik_proxy"]["image"],
|
||||||
f"ghcr.io/goauthentik/proxy:{__version__}",
|
"beryju.org/authentik/outpost-proxy:gh-master",
|
||||||
)
|
)
|
||||||
|
|
|
@ -12,11 +12,11 @@
|
||||||
"@babel/core": "^7.14.6",
|
"@babel/core": "^7.14.6",
|
||||||
"@babel/plugin-proposal-decorators": "^7.14.5",
|
"@babel/plugin-proposal-decorators": "^7.14.5",
|
||||||
"@babel/plugin-transform-runtime": "^7.14.5",
|
"@babel/plugin-transform-runtime": "^7.14.5",
|
||||||
"@babel/preset-env": "^7.14.5",
|
"@babel/preset-env": "^7.14.7",
|
||||||
"@babel/preset-typescript": "^7.14.5",
|
"@babel/preset-typescript": "^7.14.5",
|
||||||
"@fortawesome/fontawesome-free": "^5.15.3",
|
"@fortawesome/fontawesome-free": "^5.15.3",
|
||||||
"@lingui/cli": "^3.10.2",
|
"@lingui/cli": "^3.10.2",
|
||||||
"@lingui/core": "^3.10.3",
|
"@lingui/core": "^3.10.4",
|
||||||
"@lingui/macro": "^3.10.2",
|
"@lingui/macro": "^3.10.2",
|
||||||
"@patternfly/patternfly": "^4.108.2",
|
"@patternfly/patternfly": "^4.108.2",
|
||||||
"@polymer/iron-form": "^3.0.1",
|
"@polymer/iron-form": "^3.0.1",
|
||||||
|
@ -24,22 +24,22 @@
|
||||||
"@rollup/plugin-babel": "^5.3.0",
|
"@rollup/plugin-babel": "^5.3.0",
|
||||||
"@rollup/plugin-replace": "^2.4.2",
|
"@rollup/plugin-replace": "^2.4.2",
|
||||||
"@rollup/plugin-typescript": "^8.2.1",
|
"@rollup/plugin-typescript": "^8.2.1",
|
||||||
"@sentry/browser": "^6.7.1",
|
"@sentry/browser": "^6.7.2",
|
||||||
"@sentry/tracing": "^6.7.1",
|
"@sentry/tracing": "^6.7.2",
|
||||||
"@types/chart.js": "^2.9.32",
|
"@types/chart.js": "^2.9.32",
|
||||||
"@types/codemirror": "5.60.0",
|
"@types/codemirror": "5.60.0",
|
||||||
"@types/grecaptcha": "^3.0.2",
|
"@types/grecaptcha": "^3.0.2",
|
||||||
"@typescript-eslint/eslint-plugin": "^4.27.0",
|
"@typescript-eslint/eslint-plugin": "^4.28.0",
|
||||||
"@typescript-eslint/parser": "^4.27.0",
|
"@typescript-eslint/parser": "^4.28.0",
|
||||||
"@webcomponents/webcomponentsjs": "^2.5.0",
|
"@webcomponents/webcomponentsjs": "^2.5.0",
|
||||||
"authentik-api": "file:api",
|
"authentik-api": "file:api",
|
||||||
"babel-plugin-macros": "^3.1.0",
|
"babel-plugin-macros": "^3.1.0",
|
||||||
"base64-js": "^1.5.1",
|
"base64-js": "^1.5.1",
|
||||||
"chart.js": "^3.3.2",
|
"chart.js": "^3.3.2",
|
||||||
"chartjs-adapter-moment": "^1.0.0",
|
"chartjs-adapter-moment": "^1.0.0",
|
||||||
"codemirror": "^5.61.1",
|
"codemirror": "^5.62.0",
|
||||||
"construct-style-sheets-polyfill": "^2.4.16",
|
"construct-style-sheets-polyfill": "^2.4.16",
|
||||||
"eslint": "^7.28.0",
|
"eslint": "^7.29.0",
|
||||||
"eslint-config-google": "^0.14.0",
|
"eslint-config-google": "^0.14.0",
|
||||||
"eslint-plugin-custom-elements": "0.0.2",
|
"eslint-plugin-custom-elements": "0.0.2",
|
||||||
"eslint-plugin-lit": "^1.5.1",
|
"eslint-plugin-lit": "^1.5.1",
|
||||||
|
@ -48,7 +48,7 @@
|
||||||
"lit-html": "^1.4.1",
|
"lit-html": "^1.4.1",
|
||||||
"moment": "^2.29.1",
|
"moment": "^2.29.1",
|
||||||
"rapidoc": "^9.0.0",
|
"rapidoc": "^9.0.0",
|
||||||
"rollup": "^2.51.2",
|
"rollup": "^2.52.2",
|
||||||
"rollup-plugin-commonjs": "^10.1.0",
|
"rollup-plugin-commonjs": "^10.1.0",
|
||||||
"rollup-plugin-copy": "^3.4.0",
|
"rollup-plugin-copy": "^3.4.0",
|
||||||
"rollup-plugin-cssimport": "^1.0.2",
|
"rollup-plugin-cssimport": "^1.0.2",
|
||||||
|
@ -58,7 +58,7 @@
|
||||||
"rollup-plugin-terser": "^7.0.2",
|
"rollup-plugin-terser": "^7.0.2",
|
||||||
"ts-lit-plugin": "^1.2.1",
|
"ts-lit-plugin": "^1.2.1",
|
||||||
"tslib": "^2.3.0",
|
"tslib": "^2.3.0",
|
||||||
"typescript": "^4.3.2",
|
"typescript": "^4.3.4",
|
||||||
"webcomponent-qr-code": "^1.0.5",
|
"webcomponent-qr-code": "^1.0.5",
|
||||||
"yaml": "^1.10.2"
|
"yaml": "^1.10.2"
|
||||||
}
|
}
|
||||||
|
@ -102,9 +102,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/compat-data": {
|
"node_modules/@babel/compat-data": {
|
||||||
"version": "7.14.5",
|
"version": "7.14.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.14.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.14.7.tgz",
|
||||||
"integrity": "sha512-kixrYn4JwfAVPa0f2yfzc2AWti6WRRyO3XjWW5PJAvtE11qhSayrrcrEnee05KAtNaPC+EwehE8Qt1UedEVB8w==",
|
"integrity": "sha512-nS6dZaISCXJ3+518CWiBfEr//gHyMO02uDxBkXTKZDN5POruCnOZ1N4YBRZDCabwF8nZMWBpRxIicmXtBs+fvw==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
|
@ -532,9 +532,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/plugin-proposal-async-generator-functions": {
|
"node_modules/@babel/plugin-proposal-async-generator-functions": {
|
||||||
"version": "7.14.5",
|
"version": "7.14.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.14.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.14.7.tgz",
|
||||||
"integrity": "sha512-tbD/CG3l43FIXxmu4a7RBe4zH7MLJ+S/lFowPFO7HetS2hyOZ/0nnnznegDuzFzfkyQYTxqdTH/hKmuBngaDAA==",
|
"integrity": "sha512-RK8Wj7lXLY3bqei69/cc25gwS5puEc3dknoFPFbqfy3XxYQBQFvu4ioWpafMBAB+L9NyptQK4nMOa5Xz16og8Q==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-plugin-utils": "^7.14.5",
|
"@babel/helper-plugin-utils": "^7.14.5",
|
||||||
"@babel/helper-remap-async-to-generator": "^7.14.5",
|
"@babel/helper-remap-async-to-generator": "^7.14.5",
|
||||||
|
@ -685,11 +685,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/plugin-proposal-object-rest-spread": {
|
"node_modules/@babel/plugin-proposal-object-rest-spread": {
|
||||||
"version": "7.14.5",
|
"version": "7.14.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.14.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.14.7.tgz",
|
||||||
"integrity": "sha512-VzMyY6PWNPPT3pxc5hi9LloKNr4SSrVCg7Yr6aZpW4Ym07r7KqSU/QXYwjXLVxqwSv0t/XSXkFoKBPUkZ8vb2A==",
|
"integrity": "sha512-082hsZz+sVabfmDWo1Oct1u1AgbKbUAyVgmX4otIc7bdsRgHBXwTwb3DpDmD4Eyyx6DNiuz5UAATT655k+kL5g==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/compat-data": "^7.14.5",
|
"@babel/compat-data": "^7.14.7",
|
||||||
"@babel/helper-compilation-targets": "^7.14.5",
|
"@babel/helper-compilation-targets": "^7.14.5",
|
||||||
"@babel/helper-plugin-utils": "^7.14.5",
|
"@babel/helper-plugin-utils": "^7.14.5",
|
||||||
"@babel/plugin-syntax-object-rest-spread": "^7.8.3",
|
"@babel/plugin-syntax-object-rest-spread": "^7.8.3",
|
||||||
|
@ -1077,9 +1077,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/plugin-transform-destructuring": {
|
"node_modules/@babel/plugin-transform-destructuring": {
|
||||||
"version": "7.14.5",
|
"version": "7.14.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.14.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.14.7.tgz",
|
||||||
"integrity": "sha512-wU9tYisEbRMxqDezKUqC9GleLycCRoUsai9ddlsq54r8QRLaeEhc+d+9DqCG+kV9W2GgQjTZESPTpn5bAFMDww==",
|
"integrity": "sha512-0mDE99nK+kVh3xlc5vKwB6wnP9ecuSj+zQCa/n0voENtP/zymdT4HH6QEb65wjjcbqr1Jb/7z9Qp7TF5FtwYGw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-plugin-utils": "^7.14.5"
|
"@babel/helper-plugin-utils": "^7.14.5"
|
||||||
},
|
},
|
||||||
|
@ -1258,9 +1258,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/plugin-transform-named-capturing-groups-regex": {
|
"node_modules/@babel/plugin-transform-named-capturing-groups-regex": {
|
||||||
"version": "7.14.5",
|
"version": "7.14.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.14.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.14.7.tgz",
|
||||||
"integrity": "sha512-+Xe5+6MWFo311U8SchgeX5c1+lJM+eZDBZgD+tvXu9VVQPXwwVzeManMMjYX6xw2HczngfOSZjoFYKwdeB/Jvw==",
|
"integrity": "sha512-DTNOTaS7TkW97xsDMrp7nycUVh6sn/eq22VaxWfEdzuEbRsiaOU0pqU7DlyUGHVsbQbSghvjKRpEl+nUCKGQSg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-create-regexp-features-plugin": "^7.14.5"
|
"@babel/helper-create-regexp-features-plugin": "^7.14.5"
|
||||||
},
|
},
|
||||||
|
@ -1398,9 +1398,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/plugin-transform-spread": {
|
"node_modules/@babel/plugin-transform-spread": {
|
||||||
"version": "7.14.5",
|
"version": "7.14.6",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.14.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.14.6.tgz",
|
||||||
"integrity": "sha512-/3iqoQdiWergnShZYl0xACb4ADeYCJ7X/RgmwtXshn6cIvautRPAFzhd58frQlokLO6Jb4/3JXvmm6WNTPtiTw==",
|
"integrity": "sha512-Zr0x0YroFJku7n7+/HH3A2eIrGMjbmAIbJSVv0IZ+t3U2WUQUA64S/oeied2e+MaGSjmt4alzBCsK9E8gh+fag==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-plugin-utils": "^7.14.5",
|
"@babel/helper-plugin-utils": "^7.14.5",
|
||||||
"@babel/helper-skip-transparent-expression-wrappers": "^7.14.5"
|
"@babel/helper-skip-transparent-expression-wrappers": "^7.14.5"
|
||||||
|
@ -1500,16 +1500,16 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/preset-env": {
|
"node_modules/@babel/preset-env": {
|
||||||
"version": "7.14.5",
|
"version": "7.14.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.14.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.14.7.tgz",
|
||||||
"integrity": "sha512-ci6TsS0bjrdPpWGnQ+m4f+JSSzDKlckqKIJJt9UZ/+g7Zz9k0N8lYU8IeLg/01o2h8LyNZDMLGgRLDTxpudLsA==",
|
"integrity": "sha512-itOGqCKLsSUl0Y+1nSfhbuuOlTs0MJk2Iv7iSH+XT/mR8U1zRLO7NjWlYXB47yhK4J/7j+HYty/EhFZDYKa/VA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/compat-data": "^7.14.5",
|
"@babel/compat-data": "^7.14.7",
|
||||||
"@babel/helper-compilation-targets": "^7.14.5",
|
"@babel/helper-compilation-targets": "^7.14.5",
|
||||||
"@babel/helper-plugin-utils": "^7.14.5",
|
"@babel/helper-plugin-utils": "^7.14.5",
|
||||||
"@babel/helper-validator-option": "^7.14.5",
|
"@babel/helper-validator-option": "^7.14.5",
|
||||||
"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.14.5",
|
"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.14.5",
|
||||||
"@babel/plugin-proposal-async-generator-functions": "^7.14.5",
|
"@babel/plugin-proposal-async-generator-functions": "^7.14.7",
|
||||||
"@babel/plugin-proposal-class-properties": "^7.14.5",
|
"@babel/plugin-proposal-class-properties": "^7.14.5",
|
||||||
"@babel/plugin-proposal-class-static-block": "^7.14.5",
|
"@babel/plugin-proposal-class-static-block": "^7.14.5",
|
||||||
"@babel/plugin-proposal-dynamic-import": "^7.14.5",
|
"@babel/plugin-proposal-dynamic-import": "^7.14.5",
|
||||||
|
@ -1518,7 +1518,7 @@
|
||||||
"@babel/plugin-proposal-logical-assignment-operators": "^7.14.5",
|
"@babel/plugin-proposal-logical-assignment-operators": "^7.14.5",
|
||||||
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.14.5",
|
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.14.5",
|
||||||
"@babel/plugin-proposal-numeric-separator": "^7.14.5",
|
"@babel/plugin-proposal-numeric-separator": "^7.14.5",
|
||||||
"@babel/plugin-proposal-object-rest-spread": "^7.14.5",
|
"@babel/plugin-proposal-object-rest-spread": "^7.14.7",
|
||||||
"@babel/plugin-proposal-optional-catch-binding": "^7.14.5",
|
"@babel/plugin-proposal-optional-catch-binding": "^7.14.5",
|
||||||
"@babel/plugin-proposal-optional-chaining": "^7.14.5",
|
"@babel/plugin-proposal-optional-chaining": "^7.14.5",
|
||||||
"@babel/plugin-proposal-private-methods": "^7.14.5",
|
"@babel/plugin-proposal-private-methods": "^7.14.5",
|
||||||
|
@ -1544,7 +1544,7 @@
|
||||||
"@babel/plugin-transform-block-scoping": "^7.14.5",
|
"@babel/plugin-transform-block-scoping": "^7.14.5",
|
||||||
"@babel/plugin-transform-classes": "^7.14.5",
|
"@babel/plugin-transform-classes": "^7.14.5",
|
||||||
"@babel/plugin-transform-computed-properties": "^7.14.5",
|
"@babel/plugin-transform-computed-properties": "^7.14.5",
|
||||||
"@babel/plugin-transform-destructuring": "^7.14.5",
|
"@babel/plugin-transform-destructuring": "^7.14.7",
|
||||||
"@babel/plugin-transform-dotall-regex": "^7.14.5",
|
"@babel/plugin-transform-dotall-regex": "^7.14.5",
|
||||||
"@babel/plugin-transform-duplicate-keys": "^7.14.5",
|
"@babel/plugin-transform-duplicate-keys": "^7.14.5",
|
||||||
"@babel/plugin-transform-exponentiation-operator": "^7.14.5",
|
"@babel/plugin-transform-exponentiation-operator": "^7.14.5",
|
||||||
|
@ -1556,7 +1556,7 @@
|
||||||
"@babel/plugin-transform-modules-commonjs": "^7.14.5",
|
"@babel/plugin-transform-modules-commonjs": "^7.14.5",
|
||||||
"@babel/plugin-transform-modules-systemjs": "^7.14.5",
|
"@babel/plugin-transform-modules-systemjs": "^7.14.5",
|
||||||
"@babel/plugin-transform-modules-umd": "^7.14.5",
|
"@babel/plugin-transform-modules-umd": "^7.14.5",
|
||||||
"@babel/plugin-transform-named-capturing-groups-regex": "^7.14.5",
|
"@babel/plugin-transform-named-capturing-groups-regex": "^7.14.7",
|
||||||
"@babel/plugin-transform-new-target": "^7.14.5",
|
"@babel/plugin-transform-new-target": "^7.14.5",
|
||||||
"@babel/plugin-transform-object-super": "^7.14.5",
|
"@babel/plugin-transform-object-super": "^7.14.5",
|
||||||
"@babel/plugin-transform-parameters": "^7.14.5",
|
"@babel/plugin-transform-parameters": "^7.14.5",
|
||||||
|
@ -1564,7 +1564,7 @@
|
||||||
"@babel/plugin-transform-regenerator": "^7.14.5",
|
"@babel/plugin-transform-regenerator": "^7.14.5",
|
||||||
"@babel/plugin-transform-reserved-words": "^7.14.5",
|
"@babel/plugin-transform-reserved-words": "^7.14.5",
|
||||||
"@babel/plugin-transform-shorthand-properties": "^7.14.5",
|
"@babel/plugin-transform-shorthand-properties": "^7.14.5",
|
||||||
"@babel/plugin-transform-spread": "^7.14.5",
|
"@babel/plugin-transform-spread": "^7.14.6",
|
||||||
"@babel/plugin-transform-sticky-regex": "^7.14.5",
|
"@babel/plugin-transform-sticky-regex": "^7.14.5",
|
||||||
"@babel/plugin-transform-template-literals": "^7.14.5",
|
"@babel/plugin-transform-template-literals": "^7.14.5",
|
||||||
"@babel/plugin-transform-typeof-symbol": "^7.14.5",
|
"@babel/plugin-transform-typeof-symbol": "^7.14.5",
|
||||||
|
@ -1575,7 +1575,7 @@
|
||||||
"babel-plugin-polyfill-corejs2": "^0.2.2",
|
"babel-plugin-polyfill-corejs2": "^0.2.2",
|
||||||
"babel-plugin-polyfill-corejs3": "^0.2.2",
|
"babel-plugin-polyfill-corejs3": "^0.2.2",
|
||||||
"babel-plugin-polyfill-regenerator": "^0.2.2",
|
"babel-plugin-polyfill-regenerator": "^0.2.2",
|
||||||
"core-js-compat": "^3.14.0",
|
"core-js-compat": "^3.15.0",
|
||||||
"semver": "^6.3.0"
|
"semver": "^6.3.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -2047,9 +2047,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@lingui/core": {
|
"node_modules/@lingui/core": {
|
||||||
"version": "3.10.3",
|
"version": "3.10.4",
|
||||||
"resolved": "https://registry.npmjs.org/@lingui/core/-/core-3.10.3.tgz",
|
"resolved": "https://registry.npmjs.org/@lingui/core/-/core-3.10.4.tgz",
|
||||||
"integrity": "sha512-BiuWi5xPpQa27oIWWnkOYNx4qTMdMeu7vp5y1AGPYQ/4SO0rHfAtOxXtvRU/ktVwht/lIgx5Ygq5J3F+XLvOQA==",
|
"integrity": "sha512-V9QKQ9PFMTPrGGz2PaeKHZcxFikQZzJbptyQbVFJdXaKhdE2RH6HhdK1PIziDHqp6ZWPthVIfVLURT3ku8eu5w==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.11.2",
|
"@babel/runtime": "^7.11.2",
|
||||||
"make-plural": "^6.2.2",
|
"make-plural": "^6.2.2",
|
||||||
|
@ -2314,13 +2314,13 @@
|
||||||
"integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg=="
|
"integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg=="
|
||||||
},
|
},
|
||||||
"node_modules/@sentry/browser": {
|
"node_modules/@sentry/browser": {
|
||||||
"version": "6.7.1",
|
"version": "6.7.2",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-6.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-6.7.2.tgz",
|
||||||
"integrity": "sha512-R5PYx4TTvifcU790XkK6JVGwavKaXwycDU0MaAwfc4Vf7BLm5KCNJCsDySu1RPAap/017MVYf54p6dWvKiRviA==",
|
"integrity": "sha512-Lv0Ne1QcesyGAhVcQDfQa3hDPR/MhPSDTMg3xFi+LxqztchVc4w/ynzR0wCZFb8KIHpTj5SpJHfxpDhXYMtS9g==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sentry/core": "6.7.1",
|
"@sentry/core": "6.7.2",
|
||||||
"@sentry/types": "6.7.1",
|
"@sentry/types": "6.7.2",
|
||||||
"@sentry/utils": "6.7.1",
|
"@sentry/utils": "6.7.2",
|
||||||
"tslib": "^1.9.3"
|
"tslib": "^1.9.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -2333,14 +2333,14 @@
|
||||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||||
},
|
},
|
||||||
"node_modules/@sentry/core": {
|
"node_modules/@sentry/core": {
|
||||||
"version": "6.7.1",
|
"version": "6.7.2",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.7.2.tgz",
|
||||||
"integrity": "sha512-VAv8OR/7INn2JfiLcuop4hfDcyC7mfL9fdPndQEhlacjmw8gRrgXjR7qyhnCTgzFLkHI7V5bcdIzA83TRPYQpA==",
|
"integrity": "sha512-NTZqwN5nR94yrXmSfekoPs1mIFuKvf8esdIW/DadwSKWAdLJwQTJY9xK/8PQv+SEzd7wiitPAx+mCw2By1xiNQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sentry/hub": "6.7.1",
|
"@sentry/hub": "6.7.2",
|
||||||
"@sentry/minimal": "6.7.1",
|
"@sentry/minimal": "6.7.2",
|
||||||
"@sentry/types": "6.7.1",
|
"@sentry/types": "6.7.2",
|
||||||
"@sentry/utils": "6.7.1",
|
"@sentry/utils": "6.7.2",
|
||||||
"tslib": "^1.9.3"
|
"tslib": "^1.9.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -2353,12 +2353,12 @@
|
||||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||||
},
|
},
|
||||||
"node_modules/@sentry/hub": {
|
"node_modules/@sentry/hub": {
|
||||||
"version": "6.7.1",
|
"version": "6.7.2",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.7.2.tgz",
|
||||||
"integrity": "sha512-eVCTWvvcp6xa0A5GGNHMQEWslmKPlisE5rGmsV/kjvSUv3zSrI0eIDfb51ikdnCiBjHpK2NBWP8Vy8cZOEJegg==",
|
"integrity": "sha512-05qVW6ymChJsXag4+fYCQokW3AcABIgcqrVYZUBf6GMU/Gbz5SJqpV7y1+njwWvnPZydMncP9LaDVpMKbE7UYQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sentry/types": "6.7.1",
|
"@sentry/types": "6.7.2",
|
||||||
"@sentry/utils": "6.7.1",
|
"@sentry/utils": "6.7.2",
|
||||||
"tslib": "^1.9.3"
|
"tslib": "^1.9.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -2371,12 +2371,12 @@
|
||||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||||
},
|
},
|
||||||
"node_modules/@sentry/minimal": {
|
"node_modules/@sentry/minimal": {
|
||||||
"version": "6.7.1",
|
"version": "6.7.2",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.7.2.tgz",
|
||||||
"integrity": "sha512-HDDPEnQRD6hC0qaHdqqKDStcdE1KhkFh0RCtJNMCDn0zpav8Dj9AteF70x6kLSlliAJ/JFwi6AmQrLz+FxPexw==",
|
"integrity": "sha512-jkpwFv2GFHoVl5vnK+9/Q+Ea8eVdbJ3hn3/Dqq9MOLFnVK7ED6MhdHKLT79puGSFj+85OuhM5m2Q44mIhyS5mw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sentry/hub": "6.7.1",
|
"@sentry/hub": "6.7.2",
|
||||||
"@sentry/types": "6.7.1",
|
"@sentry/types": "6.7.2",
|
||||||
"tslib": "^1.9.3"
|
"tslib": "^1.9.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -2389,14 +2389,14 @@
|
||||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||||
},
|
},
|
||||||
"node_modules/@sentry/tracing": {
|
"node_modules/@sentry/tracing": {
|
||||||
"version": "6.7.1",
|
"version": "6.7.2",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-6.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-6.7.2.tgz",
|
||||||
"integrity": "sha512-wyS3nWNl5mzaC1qZ2AIp1hjXnfO9EERjMIJjCihs2LWBz1r3efxrHxJHs8wXlNWvrT3KLhq/7vvF5CdU82uPeQ==",
|
"integrity": "sha512-juKlI7FICKONWJFJxDxerj0A+8mNRhmtrdR+OXFqOkqSAy/QXlSFZcA/j//O19k2CfwK1BrvoMcQ/4gnffUOVg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sentry/hub": "6.7.1",
|
"@sentry/hub": "6.7.2",
|
||||||
"@sentry/minimal": "6.7.1",
|
"@sentry/minimal": "6.7.2",
|
||||||
"@sentry/types": "6.7.1",
|
"@sentry/types": "6.7.2",
|
||||||
"@sentry/utils": "6.7.1",
|
"@sentry/utils": "6.7.2",
|
||||||
"tslib": "^1.9.3"
|
"tslib": "^1.9.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -2409,19 +2409,19 @@
|
||||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||||
},
|
},
|
||||||
"node_modules/@sentry/types": {
|
"node_modules/@sentry/types": {
|
||||||
"version": "6.7.1",
|
"version": "6.7.2",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.7.2.tgz",
|
||||||
"integrity": "sha512-9AO7HKoip2MBMNQJEd6+AKtjj2+q9Ze4ooWUdEvdOVSt5drg7BGpK221/p9JEOyJAZwEPEXdcMd3VAIMiOb4MA==",
|
"integrity": "sha512-h21Go/PfstUN+ZV6SbwRSZVg9GXRJWdLfHoO5PSVb3TVEMckuxk8tAE57/u+UZDwX8wu+Xyon2TgsKpiWKxqUg==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sentry/utils": {
|
"node_modules/@sentry/utils": {
|
||||||
"version": "6.7.1",
|
"version": "6.7.2",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.7.2.tgz",
|
||||||
"integrity": "sha512-Tq2otdbWlHAkctD+EWTYKkEx6BL1Qn3Z/imkO06/PvzpWvVhJWQ5qHAzz5XnwwqNHyV03KVzYB6znq1Bea9HuA==",
|
"integrity": "sha512-9COL7aaBbe61Hp5BlArtXZ1o/cxli1NGONLPrVT4fMyeQFmLonhUiy77NdsW19XnvhvaA+2IoV5dg3dnFiF/og==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sentry/types": "6.7.1",
|
"@sentry/types": "6.7.2",
|
||||||
"tslib": "^1.9.3"
|
"tslib": "^1.9.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -2579,15 +2579,14 @@
|
||||||
"integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA=="
|
"integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA=="
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||||
"version": "4.27.0",
|
"version": "4.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.27.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.28.0.tgz",
|
||||||
"integrity": "sha512-DsLqxeUfLVNp3AO7PC3JyaddmEHTtI9qTSAs+RB6ja27QvIM0TA8Cizn1qcS6vOu+WDLFJzkwkgweiyFhssDdQ==",
|
"integrity": "sha512-KcF6p3zWhf1f8xO84tuBailV5cN92vhS+VT7UJsPzGBm9VnQqfI9AsiMUFUCYHTYPg1uCCo+HyiDnpDuvkAMfQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/experimental-utils": "4.27.0",
|
"@typescript-eslint/experimental-utils": "4.28.0",
|
||||||
"@typescript-eslint/scope-manager": "4.27.0",
|
"@typescript-eslint/scope-manager": "4.28.0",
|
||||||
"debug": "^4.3.1",
|
"debug": "^4.3.1",
|
||||||
"functional-red-black-tree": "^1.0.1",
|
"functional-red-black-tree": "^1.0.1",
|
||||||
"lodash": "^4.17.21",
|
|
||||||
"regexpp": "^3.1.0",
|
"regexpp": "^3.1.0",
|
||||||
"semver": "^7.3.5",
|
"semver": "^7.3.5",
|
||||||
"tsutils": "^3.21.0"
|
"tsutils": "^3.21.0"
|
||||||
|
@ -2610,14 +2609,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/experimental-utils": {
|
"node_modules/@typescript-eslint/experimental-utils": {
|
||||||
"version": "4.27.0",
|
"version": "4.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.27.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.28.0.tgz",
|
||||||
"integrity": "sha512-n5NlbnmzT2MXlyT+Y0Jf0gsmAQzCnQSWXKy4RGSXVStjDvS5we9IWbh7qRVKdGcxT0WYlgcCYUK/HRg7xFhvjQ==",
|
"integrity": "sha512-9XD9s7mt3QWMk82GoyUpc/Ji03vz4T5AYlHF9DcoFNfJ/y3UAclRsfGiE2gLfXtyC+JRA3trR7cR296TEb1oiQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/json-schema": "^7.0.7",
|
"@types/json-schema": "^7.0.7",
|
||||||
"@typescript-eslint/scope-manager": "4.27.0",
|
"@typescript-eslint/scope-manager": "4.28.0",
|
||||||
"@typescript-eslint/types": "4.27.0",
|
"@typescript-eslint/types": "4.28.0",
|
||||||
"@typescript-eslint/typescript-estree": "4.27.0",
|
"@typescript-eslint/typescript-estree": "4.28.0",
|
||||||
"eslint-scope": "^5.1.1",
|
"eslint-scope": "^5.1.1",
|
||||||
"eslint-utils": "^3.0.0"
|
"eslint-utils": "^3.0.0"
|
||||||
},
|
},
|
||||||
|
@ -2650,13 +2649,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/parser": {
|
"node_modules/@typescript-eslint/parser": {
|
||||||
"version": "4.27.0",
|
"version": "4.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.27.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.28.0.tgz",
|
||||||
"integrity": "sha512-XpbxL+M+gClmJcJ5kHnUpBGmlGdgNvy6cehgR6ufyxkEJMGP25tZKCaKyC0W/JVpuhU3VU1RBn7SYUPKSMqQvQ==",
|
"integrity": "sha512-7x4D22oPY8fDaOCvkuXtYYTQ6mTMmkivwEzS+7iml9F9VkHGbbZ3x4fHRwxAb5KeuSkLqfnYjs46tGx2Nour4A==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/scope-manager": "4.27.0",
|
"@typescript-eslint/scope-manager": "4.28.0",
|
||||||
"@typescript-eslint/types": "4.27.0",
|
"@typescript-eslint/types": "4.28.0",
|
||||||
"@typescript-eslint/typescript-estree": "4.27.0",
|
"@typescript-eslint/typescript-estree": "4.28.0",
|
||||||
"debug": "^4.3.1"
|
"debug": "^4.3.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -2676,12 +2675,12 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/scope-manager": {
|
"node_modules/@typescript-eslint/scope-manager": {
|
||||||
"version": "4.27.0",
|
"version": "4.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.27.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.28.0.tgz",
|
||||||
"integrity": "sha512-DY73jK6SEH6UDdzc6maF19AHQJBFVRf6fgAXHPXCGEmpqD4vYgPEzqpFz1lf/daSbOcMpPPj9tyXXDPW2XReAw==",
|
"integrity": "sha512-eCALCeScs5P/EYjwo6se9bdjtrh8ByWjtHzOkC4Tia6QQWtQr3PHovxh3TdYTuFcurkYI4rmFsRFpucADIkseg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "4.27.0",
|
"@typescript-eslint/types": "4.28.0",
|
||||||
"@typescript-eslint/visitor-keys": "4.27.0"
|
"@typescript-eslint/visitor-keys": "4.28.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^8.10.0 || ^10.13.0 || >=11.10.1"
|
"node": "^8.10.0 || ^10.13.0 || >=11.10.1"
|
||||||
|
@ -2692,9 +2691,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/types": {
|
"node_modules/@typescript-eslint/types": {
|
||||||
"version": "4.27.0",
|
"version": "4.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.27.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.28.0.tgz",
|
||||||
"integrity": "sha512-I4ps3SCPFCKclRcvnsVA/7sWzh7naaM/b4pBO2hVxnM3wrU51Lveybdw5WoIktU/V4KfXrTt94V9b065b/0+wA==",
|
"integrity": "sha512-p16xMNKKoiJCVZY5PW/AfILw2xe1LfruTcfAKBj3a+wgNYP5I9ZEKNDOItoRt53p4EiPV6iRSICy8EPanG9ZVA==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^8.10.0 || ^10.13.0 || >=11.10.1"
|
"node": "^8.10.0 || ^10.13.0 || >=11.10.1"
|
||||||
},
|
},
|
||||||
|
@ -2704,12 +2703,12 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/typescript-estree": {
|
"node_modules/@typescript-eslint/typescript-estree": {
|
||||||
"version": "4.27.0",
|
"version": "4.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.27.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.28.0.tgz",
|
||||||
"integrity": "sha512-KH03GUsUj41sRLLEy2JHstnezgpS5VNhrJouRdmh6yNdQ+yl8w5LrSwBkExM+jWwCJa7Ct2c8yl8NdtNRyQO6g==",
|
"integrity": "sha512-m19UQTRtxMzKAm8QxfKpvh6OwQSXaW1CdZPoCaQuLwAq7VZMNuhJmZR4g5281s2ECt658sldnJfdpSZZaxUGMQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "4.27.0",
|
"@typescript-eslint/types": "4.28.0",
|
||||||
"@typescript-eslint/visitor-keys": "4.27.0",
|
"@typescript-eslint/visitor-keys": "4.28.0",
|
||||||
"debug": "^4.3.1",
|
"debug": "^4.3.1",
|
||||||
"globby": "^11.0.3",
|
"globby": "^11.0.3",
|
||||||
"is-glob": "^4.0.1",
|
"is-glob": "^4.0.1",
|
||||||
|
@ -2730,9 +2729,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/globby": {
|
"node_modules/@typescript-eslint/typescript-estree/node_modules/globby": {
|
||||||
"version": "11.0.3",
|
"version": "11.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz",
|
||||||
"integrity": "sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==",
|
"integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"array-union": "^2.1.0",
|
"array-union": "^2.1.0",
|
||||||
"dir-glob": "^3.0.1",
|
"dir-glob": "^3.0.1",
|
||||||
|
@ -2749,11 +2748,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/visitor-keys": {
|
"node_modules/@typescript-eslint/visitor-keys": {
|
||||||
"version": "4.27.0",
|
"version": "4.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.27.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.28.0.tgz",
|
||||||
"integrity": "sha512-es0GRYNZp0ieckZ938cEANfEhsfHrzuLrePukLKtY3/KPXcq1Xd555Mno9/GOgXhKzn0QfkDLVgqWO3dGY80bg==",
|
"integrity": "sha512-PjJyTWwrlrvM5jazxYF5ZPs/nl0kHDZMVbuIcbpawVXaDPelp3+S9zpOz5RmVUfS/fD5l5+ZXNKnWhNYjPzCvw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "4.27.0",
|
"@typescript-eslint/types": "4.28.0",
|
||||||
"eslint-visitor-keys": "^2.0.0"
|
"eslint-visitor-keys": "^2.0.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -3476,9 +3475,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/codemirror": {
|
"node_modules/codemirror": {
|
||||||
"version": "5.61.1",
|
"version": "5.62.0",
|
||||||
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.61.1.tgz",
|
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.62.0.tgz",
|
||||||
"integrity": "sha512-+D1NZjAucuzE93vJGbAaXzvoBHwp9nJZWWWF9utjv25+5AZUiah6CIlfb4ikG4MoDsFsCG8niiJH5++OO2LgIQ=="
|
"integrity": "sha512-Xnl3304iCc8nyVZuRkzDVVwc794uc9QNX0UcPGeNic1fbzkSrO4l4GVXho9tRNKBgPYZXgocUqXyfIv3BILhCQ=="
|
||||||
},
|
},
|
||||||
"node_modules/collection-visit": {
|
"node_modules/collection-visit": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
|
@ -3579,9 +3578,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/core-js-compat": {
|
"node_modules/core-js-compat": {
|
||||||
"version": "3.14.0",
|
"version": "3.15.0",
|
||||||
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.14.0.tgz",
|
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.15.0.tgz",
|
||||||
"integrity": "sha512-R4NS2eupxtiJU+VwgkF9WTpnSfZW4pogwKHd8bclWU2sp93Pr5S1uYJI84cMOubJRou7bcfL0vmwtLslWN5p3A==",
|
"integrity": "sha512-8X6lWsG+s7IfOKzV93a7fRYfWRZobOfjw5V5rrq43Vh/W+V6qYxl7Akalsvgab4PFT/4L/pjQbdBUEM36NXKrw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"browserslist": "^4.16.6",
|
"browserslist": "^4.16.6",
|
||||||
"semver": "7.0.0"
|
"semver": "7.0.0"
|
||||||
|
@ -3862,9 +3861,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint": {
|
"node_modules/eslint": {
|
||||||
"version": "7.28.0",
|
"version": "7.29.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-7.28.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint/-/eslint-7.29.0.tgz",
|
||||||
"integrity": "sha512-UMfH0VSjP0G4p3EWirscJEQ/cHqnT/iuH6oNZOB94nBjWbMnhGEPxsZm1eyIW0C/9jLI0Fow4W5DXLjEI7mn1g==",
|
"integrity": "sha512-82G/JToB9qIy/ArBzIWG9xvvwL3R86AlCjtGw+A29OMZDqhTybz/MByORSukGxeI+YPCR4coYyITKk8BFH9nDA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "7.12.11",
|
"@babel/code-frame": "7.12.11",
|
||||||
"@eslint/eslintrc": "^0.4.2",
|
"@eslint/eslintrc": "^0.4.2",
|
||||||
|
@ -6771,9 +6770,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/rollup": {
|
"node_modules/rollup": {
|
||||||
"version": "2.51.2",
|
"version": "2.52.2",
|
||||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.51.2.tgz",
|
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.52.2.tgz",
|
||||||
"integrity": "sha512-ReV2eGEadA7hmXSzjxdDKs10neqH2QURf2RxJ6ayAlq93ugy6qIvXMmbc5cWMGCDh1h5T4thuWO1e2VNbMq8FA==",
|
"integrity": "sha512-4RlFC3k2BIHlUsJ9mGd8OO+9Lm2eDF5P7+6DNQOp5sx+7N/1tFM01kELfbxlMX3MxT6owvLB1ln4S3QvvQlbUA==",
|
||||||
"bin": {
|
"bin": {
|
||||||
"rollup": "dist/bin/rollup"
|
"rollup": "dist/bin/rollup"
|
||||||
},
|
},
|
||||||
|
@ -6781,7 +6780,7 @@
|
||||||
"node": ">=10.0.0"
|
"node": ">=10.0.0"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"fsevents": "~2.3.1"
|
"fsevents": "~2.3.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/rollup-plugin-commonjs": {
|
"node_modules/rollup-plugin-commonjs": {
|
||||||
|
@ -7605,9 +7604,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/typescript": {
|
"node_modules/typescript": {
|
||||||
"version": "4.3.2",
|
"version": "4.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.4.tgz",
|
||||||
"integrity": "sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw==",
|
"integrity": "sha512-uauPG7XZn9F/mo+7MrsRjyvbxFpzemRjKEZXS4AK83oP2KKOJPvb+9cO/gmnv8arWZvhnjVOXz7B49m1l0e9Ew==",
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
"tsserver": "bin/tsserver"
|
"tsserver": "bin/tsserver"
|
||||||
|
@ -8066,9 +8065,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@babel/compat-data": {
|
"@babel/compat-data": {
|
||||||
"version": "7.14.5",
|
"version": "7.14.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.14.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.14.7.tgz",
|
||||||
"integrity": "sha512-kixrYn4JwfAVPa0f2yfzc2AWti6WRRyO3XjWW5PJAvtE11qhSayrrcrEnee05KAtNaPC+EwehE8Qt1UedEVB8w=="
|
"integrity": "sha512-nS6dZaISCXJ3+518CWiBfEr//gHyMO02uDxBkXTKZDN5POruCnOZ1N4YBRZDCabwF8nZMWBpRxIicmXtBs+fvw=="
|
||||||
},
|
},
|
||||||
"@babel/core": {
|
"@babel/core": {
|
||||||
"version": "7.14.6",
|
"version": "7.14.6",
|
||||||
|
@ -8380,9 +8379,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@babel/plugin-proposal-async-generator-functions": {
|
"@babel/plugin-proposal-async-generator-functions": {
|
||||||
"version": "7.14.5",
|
"version": "7.14.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.14.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.14.7.tgz",
|
||||||
"integrity": "sha512-tbD/CG3l43FIXxmu4a7RBe4zH7MLJ+S/lFowPFO7HetS2hyOZ/0nnnznegDuzFzfkyQYTxqdTH/hKmuBngaDAA==",
|
"integrity": "sha512-RK8Wj7lXLY3bqei69/cc25gwS5puEc3dknoFPFbqfy3XxYQBQFvu4ioWpafMBAB+L9NyptQK4nMOa5Xz16og8Q==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/helper-plugin-utils": "^7.14.5",
|
"@babel/helper-plugin-utils": "^7.14.5",
|
||||||
"@babel/helper-remap-async-to-generator": "^7.14.5",
|
"@babel/helper-remap-async-to-generator": "^7.14.5",
|
||||||
|
@ -8473,11 +8472,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@babel/plugin-proposal-object-rest-spread": {
|
"@babel/plugin-proposal-object-rest-spread": {
|
||||||
"version": "7.14.5",
|
"version": "7.14.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.14.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.14.7.tgz",
|
||||||
"integrity": "sha512-VzMyY6PWNPPT3pxc5hi9LloKNr4SSrVCg7Yr6aZpW4Ym07r7KqSU/QXYwjXLVxqwSv0t/XSXkFoKBPUkZ8vb2A==",
|
"integrity": "sha512-082hsZz+sVabfmDWo1Oct1u1AgbKbUAyVgmX4otIc7bdsRgHBXwTwb3DpDmD4Eyyx6DNiuz5UAATT655k+kL5g==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/compat-data": "^7.14.5",
|
"@babel/compat-data": "^7.14.7",
|
||||||
"@babel/helper-compilation-targets": "^7.14.5",
|
"@babel/helper-compilation-targets": "^7.14.5",
|
||||||
"@babel/helper-plugin-utils": "^7.14.5",
|
"@babel/helper-plugin-utils": "^7.14.5",
|
||||||
"@babel/plugin-syntax-object-rest-spread": "^7.8.3",
|
"@babel/plugin-syntax-object-rest-spread": "^7.8.3",
|
||||||
|
@ -8732,9 +8731,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@babel/plugin-transform-destructuring": {
|
"@babel/plugin-transform-destructuring": {
|
||||||
"version": "7.14.5",
|
"version": "7.14.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.14.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.14.7.tgz",
|
||||||
"integrity": "sha512-wU9tYisEbRMxqDezKUqC9GleLycCRoUsai9ddlsq54r8QRLaeEhc+d+9DqCG+kV9W2GgQjTZESPTpn5bAFMDww==",
|
"integrity": "sha512-0mDE99nK+kVh3xlc5vKwB6wnP9ecuSj+zQCa/n0voENtP/zymdT4HH6QEb65wjjcbqr1Jb/7z9Qp7TF5FtwYGw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/helper-plugin-utils": "^7.14.5"
|
"@babel/helper-plugin-utils": "^7.14.5"
|
||||||
}
|
}
|
||||||
|
@ -8841,9 +8840,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@babel/plugin-transform-named-capturing-groups-regex": {
|
"@babel/plugin-transform-named-capturing-groups-regex": {
|
||||||
"version": "7.14.5",
|
"version": "7.14.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.14.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.14.7.tgz",
|
||||||
"integrity": "sha512-+Xe5+6MWFo311U8SchgeX5c1+lJM+eZDBZgD+tvXu9VVQPXwwVzeManMMjYX6xw2HczngfOSZjoFYKwdeB/Jvw==",
|
"integrity": "sha512-DTNOTaS7TkW97xsDMrp7nycUVh6sn/eq22VaxWfEdzuEbRsiaOU0pqU7DlyUGHVsbQbSghvjKRpEl+nUCKGQSg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/helper-create-regexp-features-plugin": "^7.14.5"
|
"@babel/helper-create-regexp-features-plugin": "^7.14.5"
|
||||||
}
|
}
|
||||||
|
@ -8926,9 +8925,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@babel/plugin-transform-spread": {
|
"@babel/plugin-transform-spread": {
|
||||||
"version": "7.14.5",
|
"version": "7.14.6",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.14.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.14.6.tgz",
|
||||||
"integrity": "sha512-/3iqoQdiWergnShZYl0xACb4ADeYCJ7X/RgmwtXshn6cIvautRPAFzhd58frQlokLO6Jb4/3JXvmm6WNTPtiTw==",
|
"integrity": "sha512-Zr0x0YroFJku7n7+/HH3A2eIrGMjbmAIbJSVv0IZ+t3U2WUQUA64S/oeied2e+MaGSjmt4alzBCsK9E8gh+fag==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/helper-plugin-utils": "^7.14.5",
|
"@babel/helper-plugin-utils": "^7.14.5",
|
||||||
"@babel/helper-skip-transparent-expression-wrappers": "^7.14.5"
|
"@babel/helper-skip-transparent-expression-wrappers": "^7.14.5"
|
||||||
|
@ -8986,16 +8985,16 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@babel/preset-env": {
|
"@babel/preset-env": {
|
||||||
"version": "7.14.5",
|
"version": "7.14.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.14.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.14.7.tgz",
|
||||||
"integrity": "sha512-ci6TsS0bjrdPpWGnQ+m4f+JSSzDKlckqKIJJt9UZ/+g7Zz9k0N8lYU8IeLg/01o2h8LyNZDMLGgRLDTxpudLsA==",
|
"integrity": "sha512-itOGqCKLsSUl0Y+1nSfhbuuOlTs0MJk2Iv7iSH+XT/mR8U1zRLO7NjWlYXB47yhK4J/7j+HYty/EhFZDYKa/VA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/compat-data": "^7.14.5",
|
"@babel/compat-data": "^7.14.7",
|
||||||
"@babel/helper-compilation-targets": "^7.14.5",
|
"@babel/helper-compilation-targets": "^7.14.5",
|
||||||
"@babel/helper-plugin-utils": "^7.14.5",
|
"@babel/helper-plugin-utils": "^7.14.5",
|
||||||
"@babel/helper-validator-option": "^7.14.5",
|
"@babel/helper-validator-option": "^7.14.5",
|
||||||
"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.14.5",
|
"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.14.5",
|
||||||
"@babel/plugin-proposal-async-generator-functions": "^7.14.5",
|
"@babel/plugin-proposal-async-generator-functions": "^7.14.7",
|
||||||
"@babel/plugin-proposal-class-properties": "^7.14.5",
|
"@babel/plugin-proposal-class-properties": "^7.14.5",
|
||||||
"@babel/plugin-proposal-class-static-block": "^7.14.5",
|
"@babel/plugin-proposal-class-static-block": "^7.14.5",
|
||||||
"@babel/plugin-proposal-dynamic-import": "^7.14.5",
|
"@babel/plugin-proposal-dynamic-import": "^7.14.5",
|
||||||
|
@ -9004,7 +9003,7 @@
|
||||||
"@babel/plugin-proposal-logical-assignment-operators": "^7.14.5",
|
"@babel/plugin-proposal-logical-assignment-operators": "^7.14.5",
|
||||||
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.14.5",
|
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.14.5",
|
||||||
"@babel/plugin-proposal-numeric-separator": "^7.14.5",
|
"@babel/plugin-proposal-numeric-separator": "^7.14.5",
|
||||||
"@babel/plugin-proposal-object-rest-spread": "^7.14.5",
|
"@babel/plugin-proposal-object-rest-spread": "^7.14.7",
|
||||||
"@babel/plugin-proposal-optional-catch-binding": "^7.14.5",
|
"@babel/plugin-proposal-optional-catch-binding": "^7.14.5",
|
||||||
"@babel/plugin-proposal-optional-chaining": "^7.14.5",
|
"@babel/plugin-proposal-optional-chaining": "^7.14.5",
|
||||||
"@babel/plugin-proposal-private-methods": "^7.14.5",
|
"@babel/plugin-proposal-private-methods": "^7.14.5",
|
||||||
|
@ -9030,7 +9029,7 @@
|
||||||
"@babel/plugin-transform-block-scoping": "^7.14.5",
|
"@babel/plugin-transform-block-scoping": "^7.14.5",
|
||||||
"@babel/plugin-transform-classes": "^7.14.5",
|
"@babel/plugin-transform-classes": "^7.14.5",
|
||||||
"@babel/plugin-transform-computed-properties": "^7.14.5",
|
"@babel/plugin-transform-computed-properties": "^7.14.5",
|
||||||
"@babel/plugin-transform-destructuring": "^7.14.5",
|
"@babel/plugin-transform-destructuring": "^7.14.7",
|
||||||
"@babel/plugin-transform-dotall-regex": "^7.14.5",
|
"@babel/plugin-transform-dotall-regex": "^7.14.5",
|
||||||
"@babel/plugin-transform-duplicate-keys": "^7.14.5",
|
"@babel/plugin-transform-duplicate-keys": "^7.14.5",
|
||||||
"@babel/plugin-transform-exponentiation-operator": "^7.14.5",
|
"@babel/plugin-transform-exponentiation-operator": "^7.14.5",
|
||||||
|
@ -9042,7 +9041,7 @@
|
||||||
"@babel/plugin-transform-modules-commonjs": "^7.14.5",
|
"@babel/plugin-transform-modules-commonjs": "^7.14.5",
|
||||||
"@babel/plugin-transform-modules-systemjs": "^7.14.5",
|
"@babel/plugin-transform-modules-systemjs": "^7.14.5",
|
||||||
"@babel/plugin-transform-modules-umd": "^7.14.5",
|
"@babel/plugin-transform-modules-umd": "^7.14.5",
|
||||||
"@babel/plugin-transform-named-capturing-groups-regex": "^7.14.5",
|
"@babel/plugin-transform-named-capturing-groups-regex": "^7.14.7",
|
||||||
"@babel/plugin-transform-new-target": "^7.14.5",
|
"@babel/plugin-transform-new-target": "^7.14.5",
|
||||||
"@babel/plugin-transform-object-super": "^7.14.5",
|
"@babel/plugin-transform-object-super": "^7.14.5",
|
||||||
"@babel/plugin-transform-parameters": "^7.14.5",
|
"@babel/plugin-transform-parameters": "^7.14.5",
|
||||||
|
@ -9050,7 +9049,7 @@
|
||||||
"@babel/plugin-transform-regenerator": "^7.14.5",
|
"@babel/plugin-transform-regenerator": "^7.14.5",
|
||||||
"@babel/plugin-transform-reserved-words": "^7.14.5",
|
"@babel/plugin-transform-reserved-words": "^7.14.5",
|
||||||
"@babel/plugin-transform-shorthand-properties": "^7.14.5",
|
"@babel/plugin-transform-shorthand-properties": "^7.14.5",
|
||||||
"@babel/plugin-transform-spread": "^7.14.5",
|
"@babel/plugin-transform-spread": "^7.14.6",
|
||||||
"@babel/plugin-transform-sticky-regex": "^7.14.5",
|
"@babel/plugin-transform-sticky-regex": "^7.14.5",
|
||||||
"@babel/plugin-transform-template-literals": "^7.14.5",
|
"@babel/plugin-transform-template-literals": "^7.14.5",
|
||||||
"@babel/plugin-transform-typeof-symbol": "^7.14.5",
|
"@babel/plugin-transform-typeof-symbol": "^7.14.5",
|
||||||
|
@ -9061,7 +9060,7 @@
|
||||||
"babel-plugin-polyfill-corejs2": "^0.2.2",
|
"babel-plugin-polyfill-corejs2": "^0.2.2",
|
||||||
"babel-plugin-polyfill-corejs3": "^0.2.2",
|
"babel-plugin-polyfill-corejs3": "^0.2.2",
|
||||||
"babel-plugin-polyfill-regenerator": "^0.2.2",
|
"babel-plugin-polyfill-regenerator": "^0.2.2",
|
||||||
"core-js-compat": "^3.14.0",
|
"core-js-compat": "^3.15.0",
|
||||||
"semver": "^6.3.0"
|
"semver": "^6.3.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -9431,9 +9430,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@lingui/core": {
|
"@lingui/core": {
|
||||||
"version": "3.10.3",
|
"version": "3.10.4",
|
||||||
"resolved": "https://registry.npmjs.org/@lingui/core/-/core-3.10.3.tgz",
|
"resolved": "https://registry.npmjs.org/@lingui/core/-/core-3.10.4.tgz",
|
||||||
"integrity": "sha512-BiuWi5xPpQa27oIWWnkOYNx4qTMdMeu7vp5y1AGPYQ/4SO0rHfAtOxXtvRU/ktVwht/lIgx5Ygq5J3F+XLvOQA==",
|
"integrity": "sha512-V9QKQ9PFMTPrGGz2PaeKHZcxFikQZzJbptyQbVFJdXaKhdE2RH6HhdK1PIziDHqp6ZWPthVIfVLURT3ku8eu5w==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/runtime": "^7.11.2",
|
"@babel/runtime": "^7.11.2",
|
||||||
"make-plural": "^6.2.2",
|
"make-plural": "^6.2.2",
|
||||||
|
@ -9670,13 +9669,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@sentry/browser": {
|
"@sentry/browser": {
|
||||||
"version": "6.7.1",
|
"version": "6.7.2",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-6.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-6.7.2.tgz",
|
||||||
"integrity": "sha512-R5PYx4TTvifcU790XkK6JVGwavKaXwycDU0MaAwfc4Vf7BLm5KCNJCsDySu1RPAap/017MVYf54p6dWvKiRviA==",
|
"integrity": "sha512-Lv0Ne1QcesyGAhVcQDfQa3hDPR/MhPSDTMg3xFi+LxqztchVc4w/ynzR0wCZFb8KIHpTj5SpJHfxpDhXYMtS9g==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@sentry/core": "6.7.1",
|
"@sentry/core": "6.7.2",
|
||||||
"@sentry/types": "6.7.1",
|
"@sentry/types": "6.7.2",
|
||||||
"@sentry/utils": "6.7.1",
|
"@sentry/utils": "6.7.2",
|
||||||
"tslib": "^1.9.3"
|
"tslib": "^1.9.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -9688,14 +9687,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@sentry/core": {
|
"@sentry/core": {
|
||||||
"version": "6.7.1",
|
"version": "6.7.2",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.7.2.tgz",
|
||||||
"integrity": "sha512-VAv8OR/7INn2JfiLcuop4hfDcyC7mfL9fdPndQEhlacjmw8gRrgXjR7qyhnCTgzFLkHI7V5bcdIzA83TRPYQpA==",
|
"integrity": "sha512-NTZqwN5nR94yrXmSfekoPs1mIFuKvf8esdIW/DadwSKWAdLJwQTJY9xK/8PQv+SEzd7wiitPAx+mCw2By1xiNQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@sentry/hub": "6.7.1",
|
"@sentry/hub": "6.7.2",
|
||||||
"@sentry/minimal": "6.7.1",
|
"@sentry/minimal": "6.7.2",
|
||||||
"@sentry/types": "6.7.1",
|
"@sentry/types": "6.7.2",
|
||||||
"@sentry/utils": "6.7.1",
|
"@sentry/utils": "6.7.2",
|
||||||
"tslib": "^1.9.3"
|
"tslib": "^1.9.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -9707,12 +9706,12 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@sentry/hub": {
|
"@sentry/hub": {
|
||||||
"version": "6.7.1",
|
"version": "6.7.2",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.7.2.tgz",
|
||||||
"integrity": "sha512-eVCTWvvcp6xa0A5GGNHMQEWslmKPlisE5rGmsV/kjvSUv3zSrI0eIDfb51ikdnCiBjHpK2NBWP8Vy8cZOEJegg==",
|
"integrity": "sha512-05qVW6ymChJsXag4+fYCQokW3AcABIgcqrVYZUBf6GMU/Gbz5SJqpV7y1+njwWvnPZydMncP9LaDVpMKbE7UYQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@sentry/types": "6.7.1",
|
"@sentry/types": "6.7.2",
|
||||||
"@sentry/utils": "6.7.1",
|
"@sentry/utils": "6.7.2",
|
||||||
"tslib": "^1.9.3"
|
"tslib": "^1.9.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -9724,12 +9723,12 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@sentry/minimal": {
|
"@sentry/minimal": {
|
||||||
"version": "6.7.1",
|
"version": "6.7.2",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.7.2.tgz",
|
||||||
"integrity": "sha512-HDDPEnQRD6hC0qaHdqqKDStcdE1KhkFh0RCtJNMCDn0zpav8Dj9AteF70x6kLSlliAJ/JFwi6AmQrLz+FxPexw==",
|
"integrity": "sha512-jkpwFv2GFHoVl5vnK+9/Q+Ea8eVdbJ3hn3/Dqq9MOLFnVK7ED6MhdHKLT79puGSFj+85OuhM5m2Q44mIhyS5mw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@sentry/hub": "6.7.1",
|
"@sentry/hub": "6.7.2",
|
||||||
"@sentry/types": "6.7.1",
|
"@sentry/types": "6.7.2",
|
||||||
"tslib": "^1.9.3"
|
"tslib": "^1.9.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -9741,14 +9740,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@sentry/tracing": {
|
"@sentry/tracing": {
|
||||||
"version": "6.7.1",
|
"version": "6.7.2",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-6.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-6.7.2.tgz",
|
||||||
"integrity": "sha512-wyS3nWNl5mzaC1qZ2AIp1hjXnfO9EERjMIJjCihs2LWBz1r3efxrHxJHs8wXlNWvrT3KLhq/7vvF5CdU82uPeQ==",
|
"integrity": "sha512-juKlI7FICKONWJFJxDxerj0A+8mNRhmtrdR+OXFqOkqSAy/QXlSFZcA/j//O19k2CfwK1BrvoMcQ/4gnffUOVg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@sentry/hub": "6.7.1",
|
"@sentry/hub": "6.7.2",
|
||||||
"@sentry/minimal": "6.7.1",
|
"@sentry/minimal": "6.7.2",
|
||||||
"@sentry/types": "6.7.1",
|
"@sentry/types": "6.7.2",
|
||||||
"@sentry/utils": "6.7.1",
|
"@sentry/utils": "6.7.2",
|
||||||
"tslib": "^1.9.3"
|
"tslib": "^1.9.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -9760,16 +9759,16 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@sentry/types": {
|
"@sentry/types": {
|
||||||
"version": "6.7.1",
|
"version": "6.7.2",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.7.2.tgz",
|
||||||
"integrity": "sha512-9AO7HKoip2MBMNQJEd6+AKtjj2+q9Ze4ooWUdEvdOVSt5drg7BGpK221/p9JEOyJAZwEPEXdcMd3VAIMiOb4MA=="
|
"integrity": "sha512-h21Go/PfstUN+ZV6SbwRSZVg9GXRJWdLfHoO5PSVb3TVEMckuxk8tAE57/u+UZDwX8wu+Xyon2TgsKpiWKxqUg=="
|
||||||
},
|
},
|
||||||
"@sentry/utils": {
|
"@sentry/utils": {
|
||||||
"version": "6.7.1",
|
"version": "6.7.2",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.7.2.tgz",
|
||||||
"integrity": "sha512-Tq2otdbWlHAkctD+EWTYKkEx6BL1Qn3Z/imkO06/PvzpWvVhJWQ5qHAzz5XnwwqNHyV03KVzYB6znq1Bea9HuA==",
|
"integrity": "sha512-9COL7aaBbe61Hp5BlArtXZ1o/cxli1NGONLPrVT4fMyeQFmLonhUiy77NdsW19XnvhvaA+2IoV5dg3dnFiF/og==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@sentry/types": "6.7.1",
|
"@sentry/types": "6.7.2",
|
||||||
"tslib": "^1.9.3"
|
"tslib": "^1.9.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -9926,29 +9925,28 @@
|
||||||
"integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA=="
|
"integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA=="
|
||||||
},
|
},
|
||||||
"@typescript-eslint/eslint-plugin": {
|
"@typescript-eslint/eslint-plugin": {
|
||||||
"version": "4.27.0",
|
"version": "4.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.27.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.28.0.tgz",
|
||||||
"integrity": "sha512-DsLqxeUfLVNp3AO7PC3JyaddmEHTtI9qTSAs+RB6ja27QvIM0TA8Cizn1qcS6vOu+WDLFJzkwkgweiyFhssDdQ==",
|
"integrity": "sha512-KcF6p3zWhf1f8xO84tuBailV5cN92vhS+VT7UJsPzGBm9VnQqfI9AsiMUFUCYHTYPg1uCCo+HyiDnpDuvkAMfQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@typescript-eslint/experimental-utils": "4.27.0",
|
"@typescript-eslint/experimental-utils": "4.28.0",
|
||||||
"@typescript-eslint/scope-manager": "4.27.0",
|
"@typescript-eslint/scope-manager": "4.28.0",
|
||||||
"debug": "^4.3.1",
|
"debug": "^4.3.1",
|
||||||
"functional-red-black-tree": "^1.0.1",
|
"functional-red-black-tree": "^1.0.1",
|
||||||
"lodash": "^4.17.21",
|
|
||||||
"regexpp": "^3.1.0",
|
"regexpp": "^3.1.0",
|
||||||
"semver": "^7.3.5",
|
"semver": "^7.3.5",
|
||||||
"tsutils": "^3.21.0"
|
"tsutils": "^3.21.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@typescript-eslint/experimental-utils": {
|
"@typescript-eslint/experimental-utils": {
|
||||||
"version": "4.27.0",
|
"version": "4.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.27.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.28.0.tgz",
|
||||||
"integrity": "sha512-n5NlbnmzT2MXlyT+Y0Jf0gsmAQzCnQSWXKy4RGSXVStjDvS5we9IWbh7qRVKdGcxT0WYlgcCYUK/HRg7xFhvjQ==",
|
"integrity": "sha512-9XD9s7mt3QWMk82GoyUpc/Ji03vz4T5AYlHF9DcoFNfJ/y3UAclRsfGiE2gLfXtyC+JRA3trR7cR296TEb1oiQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/json-schema": "^7.0.7",
|
"@types/json-schema": "^7.0.7",
|
||||||
"@typescript-eslint/scope-manager": "4.27.0",
|
"@typescript-eslint/scope-manager": "4.28.0",
|
||||||
"@typescript-eslint/types": "4.27.0",
|
"@typescript-eslint/types": "4.28.0",
|
||||||
"@typescript-eslint/typescript-estree": "4.27.0",
|
"@typescript-eslint/typescript-estree": "4.28.0",
|
||||||
"eslint-scope": "^5.1.1",
|
"eslint-scope": "^5.1.1",
|
||||||
"eslint-utils": "^3.0.0"
|
"eslint-utils": "^3.0.0"
|
||||||
},
|
},
|
||||||
|
@ -9964,37 +9962,37 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@typescript-eslint/parser": {
|
"@typescript-eslint/parser": {
|
||||||
"version": "4.27.0",
|
"version": "4.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.27.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.28.0.tgz",
|
||||||
"integrity": "sha512-XpbxL+M+gClmJcJ5kHnUpBGmlGdgNvy6cehgR6ufyxkEJMGP25tZKCaKyC0W/JVpuhU3VU1RBn7SYUPKSMqQvQ==",
|
"integrity": "sha512-7x4D22oPY8fDaOCvkuXtYYTQ6mTMmkivwEzS+7iml9F9VkHGbbZ3x4fHRwxAb5KeuSkLqfnYjs46tGx2Nour4A==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@typescript-eslint/scope-manager": "4.27.0",
|
"@typescript-eslint/scope-manager": "4.28.0",
|
||||||
"@typescript-eslint/types": "4.27.0",
|
"@typescript-eslint/types": "4.28.0",
|
||||||
"@typescript-eslint/typescript-estree": "4.27.0",
|
"@typescript-eslint/typescript-estree": "4.28.0",
|
||||||
"debug": "^4.3.1"
|
"debug": "^4.3.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@typescript-eslint/scope-manager": {
|
"@typescript-eslint/scope-manager": {
|
||||||
"version": "4.27.0",
|
"version": "4.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.27.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.28.0.tgz",
|
||||||
"integrity": "sha512-DY73jK6SEH6UDdzc6maF19AHQJBFVRf6fgAXHPXCGEmpqD4vYgPEzqpFz1lf/daSbOcMpPPj9tyXXDPW2XReAw==",
|
"integrity": "sha512-eCALCeScs5P/EYjwo6se9bdjtrh8ByWjtHzOkC4Tia6QQWtQr3PHovxh3TdYTuFcurkYI4rmFsRFpucADIkseg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@typescript-eslint/types": "4.27.0",
|
"@typescript-eslint/types": "4.28.0",
|
||||||
"@typescript-eslint/visitor-keys": "4.27.0"
|
"@typescript-eslint/visitor-keys": "4.28.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@typescript-eslint/types": {
|
"@typescript-eslint/types": {
|
||||||
"version": "4.27.0",
|
"version": "4.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.27.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.28.0.tgz",
|
||||||
"integrity": "sha512-I4ps3SCPFCKclRcvnsVA/7sWzh7naaM/b4pBO2hVxnM3wrU51Lveybdw5WoIktU/V4KfXrTt94V9b065b/0+wA=="
|
"integrity": "sha512-p16xMNKKoiJCVZY5PW/AfILw2xe1LfruTcfAKBj3a+wgNYP5I9ZEKNDOItoRt53p4EiPV6iRSICy8EPanG9ZVA=="
|
||||||
},
|
},
|
||||||
"@typescript-eslint/typescript-estree": {
|
"@typescript-eslint/typescript-estree": {
|
||||||
"version": "4.27.0",
|
"version": "4.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.27.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.28.0.tgz",
|
||||||
"integrity": "sha512-KH03GUsUj41sRLLEy2JHstnezgpS5VNhrJouRdmh6yNdQ+yl8w5LrSwBkExM+jWwCJa7Ct2c8yl8NdtNRyQO6g==",
|
"integrity": "sha512-m19UQTRtxMzKAm8QxfKpvh6OwQSXaW1CdZPoCaQuLwAq7VZMNuhJmZR4g5281s2ECt658sldnJfdpSZZaxUGMQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@typescript-eslint/types": "4.27.0",
|
"@typescript-eslint/types": "4.28.0",
|
||||||
"@typescript-eslint/visitor-keys": "4.27.0",
|
"@typescript-eslint/visitor-keys": "4.28.0",
|
||||||
"debug": "^4.3.1",
|
"debug": "^4.3.1",
|
||||||
"globby": "^11.0.3",
|
"globby": "^11.0.3",
|
||||||
"is-glob": "^4.0.1",
|
"is-glob": "^4.0.1",
|
||||||
|
@ -10003,9 +10001,9 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"globby": {
|
"globby": {
|
||||||
"version": "11.0.3",
|
"version": "11.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz",
|
||||||
"integrity": "sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==",
|
"integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"array-union": "^2.1.0",
|
"array-union": "^2.1.0",
|
||||||
"dir-glob": "^3.0.1",
|
"dir-glob": "^3.0.1",
|
||||||
|
@ -10018,11 +10016,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@typescript-eslint/visitor-keys": {
|
"@typescript-eslint/visitor-keys": {
|
||||||
"version": "4.27.0",
|
"version": "4.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.27.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.28.0.tgz",
|
||||||
"integrity": "sha512-es0GRYNZp0ieckZ938cEANfEhsfHrzuLrePukLKtY3/KPXcq1Xd555Mno9/GOgXhKzn0QfkDLVgqWO3dGY80bg==",
|
"integrity": "sha512-PjJyTWwrlrvM5jazxYF5ZPs/nl0kHDZMVbuIcbpawVXaDPelp3+S9zpOz5RmVUfS/fD5l5+ZXNKnWhNYjPzCvw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@typescript-eslint/types": "4.27.0",
|
"@typescript-eslint/types": "4.28.0",
|
||||||
"eslint-visitor-keys": "^2.0.0"
|
"eslint-visitor-keys": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -10591,9 +10589,9 @@
|
||||||
"integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4="
|
"integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4="
|
||||||
},
|
},
|
||||||
"codemirror": {
|
"codemirror": {
|
||||||
"version": "5.61.1",
|
"version": "5.62.0",
|
||||||
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.61.1.tgz",
|
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.62.0.tgz",
|
||||||
"integrity": "sha512-+D1NZjAucuzE93vJGbAaXzvoBHwp9nJZWWWF9utjv25+5AZUiah6CIlfb4ikG4MoDsFsCG8niiJH5++OO2LgIQ=="
|
"integrity": "sha512-Xnl3304iCc8nyVZuRkzDVVwc794uc9QNX0UcPGeNic1fbzkSrO4l4GVXho9tRNKBgPYZXgocUqXyfIv3BILhCQ=="
|
||||||
},
|
},
|
||||||
"collection-visit": {
|
"collection-visit": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
|
@ -10681,9 +10679,9 @@
|
||||||
"integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40="
|
"integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40="
|
||||||
},
|
},
|
||||||
"core-js-compat": {
|
"core-js-compat": {
|
||||||
"version": "3.14.0",
|
"version": "3.15.0",
|
||||||
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.14.0.tgz",
|
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.15.0.tgz",
|
||||||
"integrity": "sha512-R4NS2eupxtiJU+VwgkF9WTpnSfZW4pogwKHd8bclWU2sp93Pr5S1uYJI84cMOubJRou7bcfL0vmwtLslWN5p3A==",
|
"integrity": "sha512-8X6lWsG+s7IfOKzV93a7fRYfWRZobOfjw5V5rrq43Vh/W+V6qYxl7Akalsvgab4PFT/4L/pjQbdBUEM36NXKrw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"browserslist": "^4.16.6",
|
"browserslist": "^4.16.6",
|
||||||
"semver": "7.0.0"
|
"semver": "7.0.0"
|
||||||
|
@ -10901,9 +10899,9 @@
|
||||||
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
|
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
|
||||||
},
|
},
|
||||||
"eslint": {
|
"eslint": {
|
||||||
"version": "7.28.0",
|
"version": "7.29.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-7.28.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint/-/eslint-7.29.0.tgz",
|
||||||
"integrity": "sha512-UMfH0VSjP0G4p3EWirscJEQ/cHqnT/iuH6oNZOB94nBjWbMnhGEPxsZm1eyIW0C/9jLI0Fow4W5DXLjEI7mn1g==",
|
"integrity": "sha512-82G/JToB9qIy/ArBzIWG9xvvwL3R86AlCjtGw+A29OMZDqhTybz/MByORSukGxeI+YPCR4coYyITKk8BFH9nDA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/code-frame": "7.12.11",
|
"@babel/code-frame": "7.12.11",
|
||||||
"@eslint/eslintrc": "^0.4.2",
|
"@eslint/eslintrc": "^0.4.2",
|
||||||
|
@ -13202,11 +13200,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rollup": {
|
"rollup": {
|
||||||
"version": "2.51.2",
|
"version": "2.52.2",
|
||||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.51.2.tgz",
|
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.52.2.tgz",
|
||||||
"integrity": "sha512-ReV2eGEadA7hmXSzjxdDKs10neqH2QURf2RxJ6ayAlq93ugy6qIvXMmbc5cWMGCDh1h5T4thuWO1e2VNbMq8FA==",
|
"integrity": "sha512-4RlFC3k2BIHlUsJ9mGd8OO+9Lm2eDF5P7+6DNQOp5sx+7N/1tFM01kELfbxlMX3MxT6owvLB1ln4S3QvvQlbUA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"fsevents": "~2.3.1"
|
"fsevents": "~2.3.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rollup-plugin-commonjs": {
|
"rollup-plugin-commonjs": {
|
||||||
|
@ -13898,9 +13896,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"typescript": {
|
"typescript": {
|
||||||
"version": "4.3.2",
|
"version": "4.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.4.tgz",
|
||||||
"integrity": "sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw=="
|
"integrity": "sha512-uauPG7XZn9F/mo+7MrsRjyvbxFpzemRjKEZXS4AK83oP2KKOJPvb+9cO/gmnv8arWZvhnjVOXz7B49m1l0e9Ew=="
|
||||||
},
|
},
|
||||||
"uglify-js": {
|
"uglify-js": {
|
||||||
"version": "3.13.0",
|
"version": "3.13.0",
|
||||||
|
|
|
@ -41,11 +41,11 @@
|
||||||
"@babel/core": "^7.14.6",
|
"@babel/core": "^7.14.6",
|
||||||
"@babel/plugin-proposal-decorators": "^7.14.5",
|
"@babel/plugin-proposal-decorators": "^7.14.5",
|
||||||
"@babel/plugin-transform-runtime": "^7.14.5",
|
"@babel/plugin-transform-runtime": "^7.14.5",
|
||||||
"@babel/preset-env": "^7.14.5",
|
"@babel/preset-env": "^7.14.7",
|
||||||
"@babel/preset-typescript": "^7.14.5",
|
"@babel/preset-typescript": "^7.14.5",
|
||||||
"@fortawesome/fontawesome-free": "^5.15.3",
|
"@fortawesome/fontawesome-free": "^5.15.3",
|
||||||
"@lingui/cli": "^3.10.2",
|
"@lingui/cli": "^3.10.2",
|
||||||
"@lingui/core": "^3.10.3",
|
"@lingui/core": "^3.10.4",
|
||||||
"@lingui/macro": "^3.10.2",
|
"@lingui/macro": "^3.10.2",
|
||||||
"@patternfly/patternfly": "^4.108.2",
|
"@patternfly/patternfly": "^4.108.2",
|
||||||
"@polymer/iron-form": "^3.0.1",
|
"@polymer/iron-form": "^3.0.1",
|
||||||
|
@ -53,22 +53,22 @@
|
||||||
"@rollup/plugin-babel": "^5.3.0",
|
"@rollup/plugin-babel": "^5.3.0",
|
||||||
"@rollup/plugin-replace": "^2.4.2",
|
"@rollup/plugin-replace": "^2.4.2",
|
||||||
"@rollup/plugin-typescript": "^8.2.1",
|
"@rollup/plugin-typescript": "^8.2.1",
|
||||||
"@sentry/browser": "^6.7.1",
|
"@sentry/browser": "^6.7.2",
|
||||||
"@sentry/tracing": "^6.7.1",
|
"@sentry/tracing": "^6.7.2",
|
||||||
"@types/chart.js": "^2.9.32",
|
"@types/chart.js": "^2.9.32",
|
||||||
"@types/codemirror": "5.60.0",
|
"@types/codemirror": "5.60.0",
|
||||||
"@types/grecaptcha": "^3.0.2",
|
"@types/grecaptcha": "^3.0.2",
|
||||||
"@typescript-eslint/eslint-plugin": "^4.27.0",
|
"@typescript-eslint/eslint-plugin": "^4.28.0",
|
||||||
"@typescript-eslint/parser": "^4.27.0",
|
"@typescript-eslint/parser": "^4.28.0",
|
||||||
"@webcomponents/webcomponentsjs": "^2.5.0",
|
"@webcomponents/webcomponentsjs": "^2.5.0",
|
||||||
"authentik-api": "file:api",
|
"authentik-api": "file:api",
|
||||||
"babel-plugin-macros": "^3.1.0",
|
"babel-plugin-macros": "^3.1.0",
|
||||||
"base64-js": "^1.5.1",
|
"base64-js": "^1.5.1",
|
||||||
"chart.js": "^3.3.2",
|
"chart.js": "^3.3.2",
|
||||||
"chartjs-adapter-moment": "^1.0.0",
|
"chartjs-adapter-moment": "^1.0.0",
|
||||||
"codemirror": "^5.61.1",
|
"codemirror": "^5.62.0",
|
||||||
"construct-style-sheets-polyfill": "^2.4.16",
|
"construct-style-sheets-polyfill": "^2.4.16",
|
||||||
"eslint": "^7.28.0",
|
"eslint": "^7.29.0",
|
||||||
"eslint-config-google": "^0.14.0",
|
"eslint-config-google": "^0.14.0",
|
||||||
"eslint-plugin-custom-elements": "0.0.2",
|
"eslint-plugin-custom-elements": "0.0.2",
|
||||||
"eslint-plugin-lit": "^1.5.1",
|
"eslint-plugin-lit": "^1.5.1",
|
||||||
|
@ -77,7 +77,7 @@
|
||||||
"lit-html": "^1.4.1",
|
"lit-html": "^1.4.1",
|
||||||
"moment": "^2.29.1",
|
"moment": "^2.29.1",
|
||||||
"rapidoc": "^9.0.0",
|
"rapidoc": "^9.0.0",
|
||||||
"rollup": "^2.51.2",
|
"rollup": "^2.52.2",
|
||||||
"rollup-plugin-commonjs": "^10.1.0",
|
"rollup-plugin-commonjs": "^10.1.0",
|
||||||
"rollup-plugin-copy": "^3.4.0",
|
"rollup-plugin-copy": "^3.4.0",
|
||||||
"rollup-plugin-cssimport": "^1.0.2",
|
"rollup-plugin-cssimport": "^1.0.2",
|
||||||
|
@ -87,7 +87,7 @@
|
||||||
"rollup-plugin-terser": "^7.0.2",
|
"rollup-plugin-terser": "^7.0.2",
|
||||||
"ts-lit-plugin": "^1.2.1",
|
"ts-lit-plugin": "^1.2.1",
|
||||||
"tslib": "^2.3.0",
|
"tslib": "^2.3.0",
|
||||||
"typescript": "^4.3.2",
|
"typescript": "^4.3.4",
|
||||||
"webcomponent-qr-code": "^1.0.5",
|
"webcomponent-qr-code": "^1.0.5",
|
||||||
"yaml": "^1.10.2"
|
"yaml": "^1.10.2"
|
||||||
},
|
},
|
||||||
|
|
|
@ -68,7 +68,7 @@ html > form > input {
|
||||||
|
|
||||||
/* ensure background on non-flow pages match */
|
/* ensure background on non-flow pages match */
|
||||||
.pf-c-background-image::before {
|
.pf-c-background-image::before {
|
||||||
background-image: var(--ak-flow-background, url("/static/dist/assets/images/flow_background.jpg"));
|
background-image: var(--ak-flow-background);
|
||||||
background-position: center;
|
background-position: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ export const SUCCESS_CLASS = "pf-m-success";
|
||||||
export const ERROR_CLASS = "pf-m-danger";
|
export const ERROR_CLASS = "pf-m-danger";
|
||||||
export const PROGRESS_CLASS = "pf-m-in-progress";
|
export const PROGRESS_CLASS = "pf-m-in-progress";
|
||||||
export const CURRENT_CLASS = "pf-m-current";
|
export const CURRENT_CLASS = "pf-m-current";
|
||||||
export const VERSION = "2021.6.1-rc6";
|
export const VERSION = "2021.6.2";
|
||||||
export const PAGE_SIZE = 20;
|
export const PAGE_SIZE = 20;
|
||||||
export const EVENT_REFRESH = "ak-refresh";
|
export const EVENT_REFRESH = "ak-refresh";
|
||||||
export const EVENT_NOTIFICATION_TOGGLE = "ak-notification-toggle";
|
export const EVENT_NOTIFICATION_TOGGLE = "ak-notification-toggle";
|
||||||
|
|
|
@ -54,7 +54,9 @@ export class ModalButton extends LitElement {
|
||||||
|
|
||||||
resetForms(): void {
|
resetForms(): void {
|
||||||
this.querySelectorAll<HTMLFormElement>("[slot=form]").forEach(form => {
|
this.querySelectorAll<HTMLFormElement>("[slot=form]").forEach(form => {
|
||||||
|
if ("resetForm" in form) {
|
||||||
form?.resetForm();
|
form?.resetForm();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,9 @@ export abstract class TableModal<T> extends Table<T> {
|
||||||
|
|
||||||
resetForms(): void {
|
resetForms(): void {
|
||||||
this.querySelectorAll<HTMLFormElement>("[slot=form]").forEach(form => {
|
this.querySelectorAll<HTMLFormElement>("[slot=form]").forEach(form => {
|
||||||
|
if ("resetForm" in form) {
|
||||||
form?.resetForm();
|
form?.resetForm();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -67,6 +67,27 @@ export class AuthenticatorValidateStageForm extends ModelForm<AuthenticatorValid
|
||||||
${t`Stage-specific settings`}
|
${t`Stage-specific settings`}
|
||||||
</span>
|
</span>
|
||||||
<div slot="body" class="pf-c-form">
|
<div slot="body" class="pf-c-form">
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${t`Device classes`}
|
||||||
|
?required=${true}
|
||||||
|
name="deviceClasses">
|
||||||
|
<select name="users" class="pf-c-form-control" multiple>
|
||||||
|
<option value=${DeviceClassesEnum.Static} ?selected=${this.isDeviceClassSelected(DeviceClassesEnum.Static)}>
|
||||||
|
${t`Static Tokens`}
|
||||||
|
</option>
|
||||||
|
<option value=${DeviceClassesEnum.Totp} ?selected=${this.isDeviceClassSelected(DeviceClassesEnum.Totp)}>
|
||||||
|
${t`TOTP Authenticators`}
|
||||||
|
</option>
|
||||||
|
<option value=${DeviceClassesEnum.Webauthn} ?selected=${this.isDeviceClassSelected(DeviceClassesEnum.Webauthn)}>
|
||||||
|
${t`WebAuthn Authenticators`}
|
||||||
|
</option>
|
||||||
|
<option value=${DeviceClassesEnum.Duo} ?selected=${this.isDeviceClassSelected(DeviceClassesEnum.Duo)}>
|
||||||
|
${t`Duo Authenticators`}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
<p class="pf-c-form__helper-text">${t`Device classes which can be used to authenticate.`}</p>
|
||||||
|
<p class="pf-c-form__helper-text">${t`Hold control/command to select multiple items.`}</p>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
<ak-form-element-horizontal
|
<ak-form-element-horizontal
|
||||||
label=${t`Not configured action`}
|
label=${t`Not configured action`}
|
||||||
?required=${true}
|
?required=${true}
|
||||||
|
@ -90,27 +111,6 @@ export class AuthenticatorValidateStageForm extends ModelForm<AuthenticatorValid
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
<ak-form-element-horizontal
|
|
||||||
label=${t`Device classes`}
|
|
||||||
?required=${true}
|
|
||||||
name="deviceClasses">
|
|
||||||
<select name="users" class="pf-c-form-control" multiple>
|
|
||||||
<option value=${DeviceClassesEnum.Static} ?selected=${this.isDeviceClassSelected(DeviceClassesEnum.Static)}>
|
|
||||||
${t`Static Tokens`}
|
|
||||||
</option>
|
|
||||||
<option value=${DeviceClassesEnum.Totp} ?selected=${this.isDeviceClassSelected(DeviceClassesEnum.Totp)}>
|
|
||||||
${t`TOTP Authenticators`}
|
|
||||||
</option>
|
|
||||||
<option value=${DeviceClassesEnum.Webauthn} ?selected=${this.isDeviceClassSelected(DeviceClassesEnum.Webauthn)}>
|
|
||||||
${t`WebAuthn Authenticators`}
|
|
||||||
</option>
|
|
||||||
<option value=${DeviceClassesEnum.Duo} ?selected=${this.isDeviceClassSelected(DeviceClassesEnum.Duo)}>
|
|
||||||
${t`Duo Authenticators`}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
<p class="pf-c-form__helper-text">${t`Device classes which can be used to authenticate.`}</p>
|
|
||||||
<p class="pf-c-form__helper-text">${t`Hold control/command to select multiple items.`}</p>
|
|
||||||
</ak-form-element-horizontal>
|
|
||||||
${this.showConfigurationStage ? html`
|
${this.showConfigurationStage ? html`
|
||||||
<ak-form-element-horizontal
|
<ak-form-element-horizontal
|
||||||
label=${t`Configuration stage`}
|
label=${t`Configuration stage`}
|
||||||
|
|
|
@ -49,7 +49,7 @@ export class TenantForm extends ModelForm<Tenant, string> {
|
||||||
<input type="text" value="${first(this.instance?.domain, window.location.host)}" class="pf-c-form-control" required>
|
<input type="text" value="${first(this.instance?.domain, window.location.host)}" class="pf-c-form-control" required>
|
||||||
<p class="pf-c-form__helper-text">${t`Matching is done based on domain suffix, so if you enter domain.tld, foo.domain.tld will still match.`}</p>
|
<p class="pf-c-form__helper-text">${t`Matching is done based on domain suffix, so if you enter domain.tld, foo.domain.tld will still match.`}</p>
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
<ak-form-element-horizontal name="default">
|
<ak-form-element-horizontal name="_default">
|
||||||
<div class="pf-c-check">
|
<div class="pf-c-check">
|
||||||
<input type="checkbox" class="pf-c-check__input" ?checked=${first(this.instance?._default, false)}>
|
<input type="checkbox" class="pf-c-check__input" ?checked=${first(this.instance?._default, false)}>
|
||||||
<label class="pf-c-check__label">
|
<label class="pf-c-check__label">
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
---
|
||||||
|
title: Frontend-only development environment
|
||||||
|
---
|
||||||
|
|
||||||
|
If you want to only make changes on the UI, you don't need a backend running from source. You can user the docker-compose install with a few customizations.
|
||||||
|
|
||||||
|
1. Clone the git repo from https://github.com/goauthentik/authentik
|
||||||
|
2. In the cloned repository, follow the docker-compose installation instructions [here](../../docs/installation/docker-compose)
|
||||||
|
3. Add the following entry to your `.env` file:
|
||||||
|
|
||||||
|
```
|
||||||
|
AUTHENTIK_IMAGE=beryju.org/authentik/server
|
||||||
|
AUTHENTIK_TAG=gh-next
|
||||||
|
AUTHENTIK_OUTPOSTS__DOCKER_IMAGE_BASE=beryju.org/authentik/outpost-%(type)s:gh-next
|
||||||
|
```
|
||||||
|
|
||||||
|
This will cause authentik to use the beta images.
|
||||||
|
|
||||||
|
4. Create a `local.env.yml` file to tell authentik to use local files instead of the bundled ones:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
log_level: debug
|
||||||
|
web:
|
||||||
|
load_local_files: true
|
||||||
|
```
|
||||||
|
|
||||||
|
5. Add this volume mapping to your compose file
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '3.2'
|
||||||
|
|
||||||
|
services:
|
||||||
|
# [...]
|
||||||
|
server:
|
||||||
|
# [...]
|
||||||
|
volumes:
|
||||||
|
- ./web:/web
|
||||||
|
- ./local.env.yml:/local.env.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
This makes the local web files and the config file available to the authentik server.
|
||||||
|
|
||||||
|
6. Run `docker-compose up -d` to apply those changes to your containers.
|
||||||
|
7. Run `make gen-web` in the project root directory to generate the API Client used by the web interfaces
|
||||||
|
8. `cd web`
|
||||||
|
9. Run `npm i` and then `npm run watch` to start the build process.
|
||||||
|
|
||||||
|
You can now access authentik on http://localhost:9000 (or https://localhost:9443).
|
||||||
|
|
||||||
|
You might also want to complete the initial setup under `/if/flow/initial-setup/`.
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
title: Getting started
|
title: Full development environment
|
||||||
slug: /
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Backend
|
## Backend
|
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
title: Developer documentation
|
||||||
|
slug: /
|
||||||
|
---
|
||||||
|
|
||||||
|
Welcome to the authentik developer documentation. authentik is fully open source and can be found here: https://github.com/goauthentik/authentik
|
||||||
|
|
|
@ -29,6 +29,10 @@ All of these variables can be set to values, but you can also use a URI-like for
|
||||||
- `AUTHENTIK_REDIS__CACHE_DB`: Database for caching, defaults to 0
|
- `AUTHENTIK_REDIS__CACHE_DB`: Database for caching, defaults to 0
|
||||||
- `AUTHENTIK_REDIS__MESSAGE_QUEUE_DB`: Database for the message queue, defaults to 1
|
- `AUTHENTIK_REDIS__MESSAGE_QUEUE_DB`: Database for the message queue, defaults to 1
|
||||||
- `AUTHENTIK_REDIS__WS_DB`: Database for websocket connections, defaults to 2
|
- `AUTHENTIK_REDIS__WS_DB`: Database for websocket connections, defaults to 2
|
||||||
|
- `AUTHENTIK_REDIS__CACHE_TIMEOUT`: Timeout for cached data until it expires in seconds, defaults to 300
|
||||||
|
- `AUTHENTIK_REDIS__CACHE_TIMEOUT_FLOWS`: Timeout for cached flow plans until they expire in seconds, defaults to 300
|
||||||
|
- `AUTHENTIK_REDIS__CACHE_TIMEOUT_POLICIES`: Timeout for cached polices until they expire in seconds, defaults to 300
|
||||||
|
- `AUTHENTIK_REDIS__CACHE_TIMEOUT_REPUTATION`: Timeout for cached reputation until they expire in seconds, defaults to 300
|
||||||
|
|
||||||
## authentik Settings
|
## authentik Settings
|
||||||
|
|
||||||
|
@ -100,16 +104,16 @@ Defaults to `info`.
|
||||||
|
|
||||||
Placeholder for outpost docker images. Default: `ghcr.io/goauthentik/%(type)s:%(version)s`.
|
Placeholder for outpost docker images. Default: `ghcr.io/goauthentik/%(type)s:%(version)s`.
|
||||||
|
|
||||||
### AUTHENTIK_AUTHENTIK
|
### AUTHENTIK_AVATARS
|
||||||
|
|
||||||
- `AUTHENTIK_AUTHENTIK__AVATARS`
|
Configure how authentik should show avatars for users. Following values can be set:
|
||||||
|
|
||||||
Controls which avatars are shown. Defaults to `gravatar`. Can be set to `none` to disable avatars.
|
- `none`: Disables per-user avatars and just shows a 1x1 pixel transparent picture
|
||||||
|
- `gravatar`: Uses gravatar with the user's email address
|
||||||
|
- Any URL: If you want to use images hosted on another server, you can set any URL.
|
||||||
|
|
||||||
- `AUTHENTIK_AUTHENTIK__BRANDING__TITLE`
|
Additionally, these placeholders can be used:
|
||||||
|
|
||||||
Branding title used throughout the UI. Defaults to `authentik`.
|
- `%(username)s`: The user's username
|
||||||
|
- `%(mail_hash)s`: The email address, md5 hashed
|
||||||
- `AUTHENTIK_AUTHENTIK__BRANDING__LOGO`
|
- `%(upn)s`: The user's UPN, if set (otherwise an empty string)
|
||||||
|
|
||||||
Logo shown in the sidebar and flow executions. Defaults to `/static/dist/assets/icons/icon_left_brand.svg`
|
|
||||||
|
|
|
@ -12,11 +12,11 @@ This installation method is for test-setups and small-scale productive setups.
|
||||||
|
|
||||||
## Preparation
|
## Preparation
|
||||||
|
|
||||||
Download the latest `docker-compose.yml` from [here](https://raw.githubusercontent.com/goauthentik/authentik/version/2021.6.1-rc6/docker-compose.yml). Place it in a directory of your choice.
|
Download the latest `docker-compose.yml` from [here](https://raw.githubusercontent.com/goauthentik/authentik/version/2021.6.2/docker-compose.yml). Place it in a directory of your choice.
|
||||||
|
|
||||||
To optionally enable error-reporting, run `echo AUTHENTIK_ERROR_REPORTING__ENABLED=true >> .env`
|
To optionally enable error-reporting, run `echo AUTHENTIK_ERROR_REPORTING__ENABLED=true >> .env`
|
||||||
|
|
||||||
To optionally deploy a different version run `echo AUTHENTIK_TAG=2021.6.1-rc6 >> .env`
|
To optionally deploy a different version run `echo AUTHENTIK_TAG=2021.6.2 >> .env`
|
||||||
|
|
||||||
If this is a fresh authentik install run the following commands to generate a password:
|
If this is a fresh authentik install run the following commands to generate a password:
|
||||||
|
|
||||||
|
@ -74,7 +74,6 @@ Afterwards, run these commands to finish
|
||||||
```shell
|
```shell
|
||||||
docker-compose pull
|
docker-compose pull
|
||||||
docker-compose up -d
|
docker-compose up -d
|
||||||
docker-compose run --rm server migrate
|
|
||||||
```
|
```
|
||||||
|
|
||||||
The compose file statically references the latest version available at the time of downloading, which can be overridden with the `SERVER_TAG` environment variable.
|
The compose file statically references the latest version available at the time of downloading, which can be overridden with the `SERVER_TAG` environment variable.
|
||||||
|
|
|
@ -55,13 +55,19 @@ Under Attribute mapping, set these values:
|
||||||
- Attribute to map the email address to.: `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress`
|
- Attribute to map the email address to.: `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress`
|
||||||
- Attribute to map the users groups to.: `http://schemas.xmlsoap.org/claims/Group`
|
- Attribute to map the users groups to.: `http://schemas.xmlsoap.org/claims/Group`
|
||||||
|
|
||||||
|
:::note
|
||||||
|
If Nextcloud is behind a reverse proxy you may need to force Nextcloud to use HTTPS.
|
||||||
|
To do this you will need to add the line `'overwriteprotocol' => 'https'` to `config.php` in the Nextcloud `config\config.php` file
|
||||||
|
See https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/reverse_proxy_configuration.html#overwrite-parameters for additional information
|
||||||
|
:::
|
||||||
|
|
||||||
## Group Quotas
|
## Group Quotas
|
||||||
|
|
||||||
Create a group for each different level of quota you want users to have. Set a custom attribute, for example called `nextcloud_quota`, to the quota you want, for example `15 GB`.
|
Create a group for each different level of quota you want users to have. Set a custom attribute, for example called `nextcloud_quota`, to the quota you want, for example `15 GB`.
|
||||||
|
|
||||||
Afterwards, create a custom SAML Property Mapping with the name `SAML NextCloud Quota`.
|
Afterwards, create a custom SAML Property Mapping with the name `SAML NextCloud Quota`.
|
||||||
Set the *SAML Name* to `nextcloud_quota`.
|
Set the *SAML Name* to `nextcloud_quota`.
|
||||||
Set the *Expression* to `return user.group_attributes.get("nextcloud_quota", "1 GB")`, where `1 GB` is the default value for users that don't belong to another group (or have another value set).
|
Set the *Expression* to `return user.group_attributes().get("nextcloud_quota", "1 GB")`, where `1 GB` is the default value for users that don't belong to another group (or have another value set).
|
||||||
|
|
||||||
## Admin Group
|
## Admin Group
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
---
|
||||||
|
title: Wekan
|
||||||
|
---
|
||||||
|
|
||||||
|
## What is Wekan
|
||||||
|
|
||||||
|
From https://github.com/wekan/wekan/wiki
|
||||||
|
|
||||||
|
:::note
|
||||||
|
Wekan is an open-source kanban board which allows a card-based task and to-do management.
|
||||||
|
:::
|
||||||
|
|
||||||
|
## Preparation
|
||||||
|
|
||||||
|
The following placeholders will be used:
|
||||||
|
|
||||||
|
- `wekan.company` is the FQDN of the wekan install.
|
||||||
|
- `authentik.company` is the FQDN of the authentik install.
|
||||||
|
|
||||||
|
Create an application in authentik. Create an OAuth2/OpenID provider with the following parameters:
|
||||||
|
|
||||||
|
- Client Type: `Confidential`
|
||||||
|
- JWT Algorithm: `RS256`
|
||||||
|
- Scopes: OpenID, Email and Profile
|
||||||
|
- RSA Key: Select any available key
|
||||||
|
- Redirect URIs: `https://wekan.company/_oauth/oidc`
|
||||||
|
|
||||||
|
Note the Client ID and Client Secret values. Create an application, using the provider you've created above. Note the slug of the application you've created.
|
||||||
|
|
||||||
|
## Wekan
|
||||||
|
|
||||||
|
import Tabs from '@theme/Tabs';
|
||||||
|
import TabItem from '@theme/TabItem';
|
||||||
|
|
||||||
|
<Tabs
|
||||||
|
defaultValue="docker"
|
||||||
|
values={[
|
||||||
|
{label: 'Docker', value: 'docker'},
|
||||||
|
{label: 'Standalone', value: 'standalone'},
|
||||||
|
]}>
|
||||||
|
<TabItem value="docker">
|
||||||
|
If your Wekan is running in docker, add the following environment variables for Authentik
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
environment:
|
||||||
|
OAUTH2_ENABLED=true
|
||||||
|
OAUTH2_LOGIN_STYLE=redirect
|
||||||
|
OAUTH2_CLIENT_ID=<Client ID from above>
|
||||||
|
OAUTH2_SERVER_URL=https://authentik.company
|
||||||
|
OAUTH2_AUTH_ENDPOINT=/application/o/authorize/
|
||||||
|
OAUTH2_USERINFO_ENDPOINT=/application/o/userinfo/
|
||||||
|
OAUTH2_TOKEN_ENDPOINT=/application/o/token/
|
||||||
|
OAUTH2_SECRET=<Client Secret from above>
|
||||||
|
OAUTH2_ID_MAP=preferred_username
|
||||||
|
OAUTH2_USERNAME_MAP=preferred_username
|
||||||
|
OAUTH2_FULLNAME_MAP=given_name
|
||||||
|
OAUTH2_EMAIL_MAP=email
|
||||||
|
```
|
||||||
|
</TabItem>
|
||||||
|
<TabItem value="standalone">
|
||||||
|
|
||||||
|
edit `.env` and add the following:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
# Authentik OAUTH Config
|
||||||
|
OAUTH2_ENABLED='true'
|
||||||
|
OAUTH2_LOGIN_STYLE='redirect'
|
||||||
|
OAUTH2_CLIENT_ID='<Client ID from above>'
|
||||||
|
OAUTH2_SERVER_URL='https://authentik.company'
|
||||||
|
OAUTH2_AUTH_ENDPOINT='/application/o/authorize/'
|
||||||
|
OAUTH2_USERINFO_ENDPOINT='/application/o/userinfo/'
|
||||||
|
OAUTH2_TOKEN_ENDPOINT='/application/o/token/'
|
||||||
|
OAUTH2_SECRET='<Client Secret from above>'
|
||||||
|
OAUTH2_ID_MAP='preferred_username'
|
||||||
|
OAUTH2_USERNAME_MAP='preferred_username'
|
||||||
|
OAUTH2_FULLNAME_MAP='given_name'
|
||||||
|
OAUTH2_EMAIL_MAP='email'
|
||||||
|
```
|
||||||
|
</TabItem>
|
||||||
|
</Tabs>
|
|
@ -39,6 +39,8 @@ Set the Field `Username attribute` to `http://schemas.goauthentik.io/2021/02/sam
|
||||||
|
|
||||||
Set the Field `SP entity ID` to `https://authentik.company/application/saml/zabbix/sso/binding/redirect/`
|
Set the Field `SP entity ID` to `https://authentik.company/application/saml/zabbix/sso/binding/redirect/`
|
||||||
|
|
||||||
|
Set the Field `SP name ID format` to `urn:oasis:names:tc:SAML:2.0:nameid-format:transient`
|
||||||
|
|
||||||
Check the box for `Case sensitive login`.
|
Check the box for `Case sensitive login`.
|
||||||
|
|
||||||
For the `SAML Service Provider Certificate` and `SAML Service Provider Private Key`, you can either use custom certificates, or use the self-signed pair generated by authentik.
|
For the `SAML Service Provider Certificate` and `SAML Service Provider Private Key`, you can either use custom certificates, or use the self-signed pair generated by authentik.
|
||||||
|
|
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 115 KiB |
After Width: | Height: | Size: 103 KiB |
After Width: | Height: | Size: 60 KiB |
|
@ -0,0 +1,54 @@
|
||||||
|
---
|
||||||
|
title: Discord
|
||||||
|
---
|
||||||
|
|
||||||
|
Allows users to authenticate using their Discord credentials
|
||||||
|
|
||||||
|
## Preparation
|
||||||
|
|
||||||
|
The following placeholders will be used:
|
||||||
|
|
||||||
|
- `authentik.company` is the FQDN of the authentik install.
|
||||||
|
|
||||||
|
|
||||||
|
## Discord
|
||||||
|
|
||||||
|
1. Create an application in the Discord Developer Portal (This is Free) https://discord.com/developers/applications
|
||||||
|
|
||||||
|
![New Application Button](discord1.png)
|
||||||
|
|
||||||
|
2. Name the Application
|
||||||
|
|
||||||
|
![Name App](discord2.png)
|
||||||
|
|
||||||
|
3. Select **OAuth2** from the left Menu
|
||||||
|
|
||||||
|
4. Copy the **Client ID** and _save it for later_
|
||||||
|
|
||||||
|
5. **Click to Reveal** the Client Secret and _save it for later_
|
||||||
|
|
||||||
|
6. Click **Add Redirect** and add https://authentik.company/source/oauth/callback/discord
|
||||||
|
|
||||||
|
Here is an example of a completed OAuth2 screen for Discord.
|
||||||
|
|
||||||
|
![Example Screen](discord4.png)
|
||||||
|
|
||||||
|
## Authentik
|
||||||
|
|
||||||
|
8. Under _Resources -> Sources_ Click **Create Discord OAuth Source**
|
||||||
|
|
||||||
|
9. **Name:** Choose a name (For the example I used Discord)
|
||||||
|
10. **Slug:** discord (You can choose a different slug, if you do you will need to update the Discord redirect URLand point it to the correct slug.)
|
||||||
|
11. **Consumer Key:** Client ID from step 4
|
||||||
|
12. **Consumer Secret:** Client Secret from step 5
|
||||||
|
13. **Provider type:** Discord
|
||||||
|
|
||||||
|
Here is an exmple of a complete Authentik Discord OAuth Source
|
||||||
|
|
||||||
|
![Example Screen](discord5.png)
|
||||||
|
|
||||||
|
Save, and you now have Discord as a source.
|
||||||
|
|
||||||
|
:::note
|
||||||
|
For more details on how-to have the new source display on the Login Page see the Sources page
|
||||||
|
:::
|
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 52 KiB |
|
@ -0,0 +1,60 @@
|
||||||
|
---
|
||||||
|
title: Github
|
||||||
|
---
|
||||||
|
|
||||||
|
Allows users to authenticate using their Github credentials
|
||||||
|
|
||||||
|
## Preparation
|
||||||
|
|
||||||
|
The following placeholders will be used:
|
||||||
|
|
||||||
|
- `authentik.company` is the FQDN of the authentik install.
|
||||||
|
- `www.my.company` Homepage URL for your site
|
||||||
|
|
||||||
|
## Github
|
||||||
|
|
||||||
|
1. Create an OAuth app under Developer Settings https://github.com/settings/developers by clicking on the **Register a neww application**
|
||||||
|
|
||||||
|
![Register OAuth App](githubdeveloper1.png)
|
||||||
|
|
||||||
|
2. **Application Name:** Choose a name users will recognize ie: Authentik
|
||||||
|
3. **Homepage URL**:: www.my.company
|
||||||
|
4. **Authorization callback URL**: https://authentik.company/source/oauth/callback/github
|
||||||
|
5. Click **Register Application**
|
||||||
|
|
||||||
|
Example screenshot
|
||||||
|
|
||||||
|
![Example Screen](githubdeveloperexample.png)
|
||||||
|
|
||||||
|
6. Copy the **Client ID** and _save it for later_
|
||||||
|
7. Click **Generate a new client secret** and _save it for later_ You will not be able to see the secret again, so be sure to copy it now.
|
||||||
|
|
||||||
|
## Authentik
|
||||||
|
|
||||||
|
8. Under _Resources -> Sources_ Click **Create Github OAuth Source**
|
||||||
|
|
||||||
|
9. **Name**: Choose a name (For the example I use Github)
|
||||||
|
10. **Slug**: github (If you choose a different slug the URLs will need to be updated to reflect the change)
|
||||||
|
11. **Consumer Key:** Client ID from step 6
|
||||||
|
12. **Consumer Secret:** Client Secret from step 7
|
||||||
|
13. **Provider Type:** Github
|
||||||
|
|
||||||
|
Expand URL settings:
|
||||||
|
|
||||||
|
:::note
|
||||||
|
As of June 20 2021 these URLS are correct. Here is the Github reference URL https://docs.github.com/en/developers/apps/building-oauth-apps/authorizing-oauth-apps
|
||||||
|
:::
|
||||||
|
|
||||||
|
14. **Authorization URL:** `https://github.com/login/oauth/authorize`
|
||||||
|
15. **Access token URL:** `https://github.com/login/oauth/access_token`
|
||||||
|
16. **Profile URL:** `https://api.github.com/user`
|
||||||
|
|
||||||
|
Here is an exmple of a complete Authentik Github OAuth Source
|
||||||
|
|
||||||
|
![Example Screen](githubexample2.png)
|
||||||
|
|
||||||
|
Save, and you now have Github as a source.
|
||||||
|
|
||||||
|
:::note
|
||||||
|
For more details on how-to have the new source display on the Login Page see the Sources page
|
||||||
|
:::
|
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 103 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 51 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 56 KiB |
|
@ -0,0 +1,83 @@
|
||||||
|
---
|
||||||
|
title: Google
|
||||||
|
---
|
||||||
|
|
||||||
|
Allows users to authenticate using their Google credentials
|
||||||
|
|
||||||
|
## Preparation
|
||||||
|
|
||||||
|
The following placeholders will be used:
|
||||||
|
|
||||||
|
- `authentik.company` is the FQDN of the authentik install.
|
||||||
|
|
||||||
|
## Google
|
||||||
|
|
||||||
|
You will need to create a new project, and OAuth credentials in the Google Developer console. The developer console can be overwhelming at first.
|
||||||
|
|
||||||
|
1. Visit https://console.developers.google.com/ to create a new project
|
||||||
|
2. Create a New project.
|
||||||
|
|
||||||
|
![Example Screen](googledeveloper1.png)
|
||||||
|
|
||||||
|
3. **Project Name**: Choose a name
|
||||||
|
4. **Organization**: Leave as defaut if unsure
|
||||||
|
5. **Location**: Leave as default if unsure
|
||||||
|
|
||||||
|
![Example Screen](googledeveloper2.png)
|
||||||
|
|
||||||
|
6. Click **Create**
|
||||||
|
7. Choose your project from the drop down at the top
|
||||||
|
8. Click the **Credentials** menu item on the left. It looks like a key.
|
||||||
|
|
||||||
|
![Example Screen](googledeveloper3.png)
|
||||||
|
|
||||||
|
9. Click on **Configure Consent Screen**
|
||||||
|
|
||||||
|
![Example Screen](googledeveloper4.png)
|
||||||
|
|
||||||
|
|
||||||
|
10. **User Type:** If you do not have a Google Workspace (GSuite) account choose _External_. If you do have a Google Workspace (Gsuite) account and want to limit acces to only users inside of your organization choose _Internal_
|
||||||
|
|
||||||
|
_I'm only going to list the mandatory/important fields to complete._
|
||||||
|
|
||||||
|
11. **App Name:** Choose an Application
|
||||||
|
12. **User Support Email:** Must have a value
|
||||||
|
13. **Authorized Domains:** authentik.company
|
||||||
|
14. **Developer Contact Info:** Must have a value
|
||||||
|
15. Click **Save and Continue**
|
||||||
|
16. If you have special scopes configured for google, enter them on this screen. If not click **Save and Continue**
|
||||||
|
17. If you want to create Test Users enter them here, if not click **Save and Continue**
|
||||||
|
18. From the _Summary Page_ click on the **Credentials* link on the left. Same link as step 8
|
||||||
|
19. Click **Create Credentials** on the top of the screen
|
||||||
|
20. Choose **OAuth Client ID**
|
||||||
|
|
||||||
|
![Example Screen](googledeveloper5.png)
|
||||||
|
|
||||||
|
21. **Application Type:** Web Application
|
||||||
|
22. **Name:** Choose a name
|
||||||
|
23. **Authorized redirect URIs:** `https://authenik.company/source/oauth/callback/google/`
|
||||||
|
|
||||||
|
![Example Screen](googledeveloper6.png)
|
||||||
|
|
||||||
|
24. Click **Create**
|
||||||
|
25. Copy and store _Your Client ID_ and _Your Client Secret_ for later
|
||||||
|
|
||||||
|
## Authentik
|
||||||
|
|
||||||
|
26. Under _Resources -> Sources_ Click **Create Google OAuth Source**
|
||||||
|
|
||||||
|
27. **Name**: Choose a name (For the example I use Google)
|
||||||
|
28. **Slug**: google (If you choose a different slug the URLs will need to be updated to reflect the change)
|
||||||
|
29. **Consumer Key:** Your Client ID from step 25
|
||||||
|
30. **Consumer Secret:** Your Client Secret from step 25
|
||||||
|
31. **Provider Type:** Google
|
||||||
|
|
||||||
|
Here is an exmple of a complete Authentik Google OAuth Source
|
||||||
|
|
||||||
|
![Example Screen](authentiksource.png)
|
||||||
|
|
||||||
|
Save, and you now have Google as a source.
|
||||||
|
|
||||||
|
:::note
|
||||||
|
For more details on how-to have the new source display on the Login Page see the Sources page
|
||||||
|
:::
|
|
@ -0,0 +1,14 @@
|
||||||
|
---
|
||||||
|
title: Sources
|
||||||
|
---
|
||||||
|
|
||||||
|
Sources allow you to connect authentik to an existing user directory. They can also be used for social logins, using external providers such as Facebook, Twitter, etc.
|
||||||
|
|
||||||
|
### Add Sources to Default Login Page
|
||||||
|
|
||||||
|
To have sources show on the default login screen you will need to add them. This is assuming you have not created or renamed the default stages and flows.
|
||||||
|
1. Access the **Flows** section
|
||||||
|
2. Click on **default-authentication-flow**
|
||||||
|
3. Click the **Stage Bindings** tab
|
||||||
|
4. Chose **Edit Stage** for the _default-authentication-identification_ stage
|
||||||
|
5. Under **Sources** you should see the addtional sources you have configured. Click all applicable sources to have them displayed on the Login Page
|