Compare commits
	
		
			73 Commits
		
	
	
		
			version/0.
			...
			version/0.
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| e23afd18e4 | |||
| c2a30b760a | |||
| 6e24856d45 | |||
| 98a58b74e3 | |||
| 5f3ab22bea | |||
| 1ed5d5da35 | |||
| 76193e0031 | |||
| 50109ca7ad | |||
| e4b66d991c | |||
| 68adc2d5a5 | |||
| 349a3a67d5 | |||
| e1394207e7 | |||
| f265c1f10b | |||
| 1aecdc7f8f | |||
| a18edaf62b | |||
| c91abe448c | |||
| e531e52403 | |||
| cae536fa65 | |||
| 316b15b8a9 | |||
| e6ccd4fa76 | |||
| 86aabba3ed | |||
| 0b36aad5c8 | |||
| 64d2a216f0 | |||
| a5e5e140d6 | |||
| 29f98abd00 | |||
| 7b5ce4e98a | |||
| d7fa52ebf3 | |||
| 2ffaa94825 | |||
| b80b2626a6 | |||
| 3b7bba5a62 | |||
| 2d9efe035e | |||
| 48438e28fd | |||
| 885a2f0a58 | |||
| cf46ee06b7 | |||
| 9e33b49d29 | |||
| 1179ba4ef2 | |||
| 3c12c8b3ff | |||
| 4d22659b6e | |||
| 2c0709eeee | |||
| c24d1b6b84 | |||
| 040e148a73 | |||
| b85d550ee0 | |||
| ce95139d66 | |||
| 46436a5780 | |||
| 835a9aaaf2 | |||
| 42005e7def | |||
| d9956e1e9c | |||
| 4b1e73251a | |||
| 736dbdca33 | |||
| 789b8e5d3e | |||
| 074b55f66b | |||
| d9bc5ea4d1 | |||
| 716bb9f188 | |||
| dd496619a2 | |||
| 51d07f7913 | |||
| 5c4163579b | |||
| 5a73413d58 | |||
| 51a5d4bf49 | |||
| 8bbb854073 | |||
| 9f2e9e8444 | |||
| a3d361f500 | |||
| e9bb583b32 | |||
| efccf47c83 | |||
| a5b144cf8f | |||
| afc5a17fc2 | |||
| b3e0884b2e | |||
| 078d648551 | |||
| 41f9097592 | |||
| 562175741c | |||
| 24e24cb97e | |||
| 69b0a23a7d | |||
| f0f3245388 | |||
| 99ca0d1f9f | 
| @ -1,5 +1,5 @@ | ||||
| [bumpversion] | ||||
| current_version = 0.13.0-rc4 | ||||
| current_version = 0.13.3-stable | ||||
| tag = True | ||||
| commit = True | ||||
| parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)\-(?P<release>.*) | ||||
|  | ||||
							
								
								
									
										14
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							| @ -18,11 +18,11 @@ jobs: | ||||
|       - name: Building Docker Image | ||||
|         run: docker build | ||||
|           --no-cache | ||||
|           -t beryju/authentik:0.13.0-rc4 | ||||
|           -t beryju/authentik:0.13.3-stable | ||||
|           -t beryju/authentik:latest | ||||
|           -f Dockerfile . | ||||
|       - name: Push Docker Container to Registry (versioned) | ||||
|         run: docker push beryju/authentik:0.13.0-rc4 | ||||
|         run: docker push beryju/authentik:0.13.3-stable | ||||
|       - name: Push Docker Container to Registry (latest) | ||||
|         run: docker push beryju/authentik:latest | ||||
|   build-proxy: | ||||
| @ -48,11 +48,11 @@ jobs: | ||||
|           cd proxy/ | ||||
|           docker build \ | ||||
|           --no-cache \ | ||||
|           -t beryju/authentik-proxy:0.13.0-rc4 \ | ||||
|           -t beryju/authentik-proxy:0.13.3-stable \ | ||||
|           -t beryju/authentik-proxy:latest \ | ||||
|           -f Dockerfile . | ||||
|       - name: Push Docker Container to Registry (versioned) | ||||
|         run: docker push beryju/authentik-proxy:0.13.0-rc4 | ||||
|         run: docker push beryju/authentik-proxy:0.13.3-stable | ||||
|       - name: Push Docker Container to Registry (latest) | ||||
|         run: docker push beryju/authentik-proxy:latest | ||||
|   build-static: | ||||
| @ -69,11 +69,11 @@ jobs: | ||||
|           cd web/ | ||||
|           docker build \ | ||||
|           --no-cache \ | ||||
|           -t beryju/authentik-static:0.13.0-rc4 \ | ||||
|           -t beryju/authentik-static:0.13.3-stable \ | ||||
|           -t beryju/authentik-static:latest \ | ||||
|           -f Dockerfile . | ||||
|       - name: Push Docker Container to Registry (versioned) | ||||
|         run: docker push beryju/authentik-static:0.13.0-rc4 | ||||
|         run: docker push beryju/authentik-static:0.13.3-stable | ||||
|       - name: Push Docker Container to Registry (latest) | ||||
|         run: docker push beryju/authentik-static:latest | ||||
|   test-release: | ||||
| @ -107,5 +107,5 @@ jobs: | ||||
|           SENTRY_PROJECT: authentik | ||||
|           SENTRY_URL: https://sentry.beryju.org | ||||
|         with: | ||||
|           tagName: 0.13.0-rc4 | ||||
|           tagName: 0.13.3-stable | ||||
|           environment: beryjuorg-prod | ||||
|  | ||||
							
								
								
									
										150
									
								
								Pipfile.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										150
									
								
								Pipfile.lock
									
									
									
										generated
									
									
									
								
							| @ -53,10 +53,10 @@ | ||||
|         }, | ||||
|         "autobahn": { | ||||
|             "hashes": [ | ||||
|                 "sha256:24ce276d313e84d68241c3aef30d484f352b90a40168981b3640312c821df77b", | ||||
|                 "sha256:86bbce30cdd407137c57670993a8f9bfdfe3f8e994b889181d85e844d5aa8dfb" | ||||
|                 "sha256:491238c31f78721eaa9d0593909ab455a4ea68127aadd76ecf67185143f5f298", | ||||
|                 "sha256:72b68a1ce1e10e3cbcc3b280aae86d5b2e7a1f409febab1ab91a8a3274113f6e" | ||||
|             ], | ||||
|             "version": "==20.7.1" | ||||
|             "version": "==20.12.2" | ||||
|         }, | ||||
|         "automat": { | ||||
|             "hashes": [ | ||||
| @ -74,18 +74,18 @@ | ||||
|         }, | ||||
|         "boto3": { | ||||
|             "hashes": [ | ||||
|                 "sha256:616cde1e326949020da85a5bacaa7ad287e9f117d10ac9c5bfb9150a98dfe1a7", | ||||
|                 "sha256:ddad9ada00eccae1fc2da28c69531ba202fead562994ddcd9a9a232e993cd8a2" | ||||
|                 "sha256:a05614300fd404c7952a55ae92e106b9400ae65886425aaab3104527be833848", | ||||
|                 "sha256:c7556b0861d982b71043fbc0df024644320c817ad796391c442d0c2f15a77223" | ||||
|             ], | ||||
|             "index": "pypi", | ||||
|             "version": "==1.16.34" | ||||
|             "version": "==1.16.39" | ||||
|         }, | ||||
|         "botocore": { | ||||
|             "hashes": [ | ||||
|                 "sha256:49f5e56a7382a65ee0873371edcd91bdba8fc3f70abe102ebc1a0da2e6fbed06", | ||||
|                 "sha256:4d81d92127ef646ae0f0ee84c9c220c92fa82312e765c29f8cb3b000fdbdd038" | ||||
|                 "sha256:449e4196160ff58ee27d2a626a7ce4cfff2640fe1806d7a279e73a30ad286347", | ||||
|                 "sha256:e0d0386098a072abd7b6c087e6149d997377c969a823ebe01b3f5bfabe9bfac0" | ||||
|             ], | ||||
|             "version": "==1.19.34" | ||||
|             "version": "==1.19.39" | ||||
|         }, | ||||
|         "cachetools": { | ||||
|             "hashes": [ | ||||
| @ -96,11 +96,11 @@ | ||||
|         }, | ||||
|         "celery": { | ||||
|             "hashes": [ | ||||
|                 "sha256:45bb7909061862305cefec94289fabc1b89ac004680f4dc7d9dea642a2507e53", | ||||
|                 "sha256:533f3635065b7ed362ffc04228635b4c82d53a9ab812118ccdedb5eae281fb97" | ||||
|                 "sha256:5e8d364e058554e83bbb116e8377d90c79be254785f357cb2cec026e79febe13", | ||||
|                 "sha256:f4efebe6f8629b0da2b8e529424de376494f5b7a743c321c8a2ddc2b1414921c" | ||||
|             ], | ||||
|             "index": "pypi", | ||||
|             "version": "==5.0.4" | ||||
|             "version": "==5.0.5" | ||||
|         }, | ||||
|         "certifi": { | ||||
|             "hashes": [ | ||||
| @ -168,10 +168,10 @@ | ||||
|         }, | ||||
|         "chardet": { | ||||
|             "hashes": [ | ||||
|                 "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", | ||||
|                 "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" | ||||
|                 "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa", | ||||
|                 "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5" | ||||
|             ], | ||||
|             "version": "==3.0.4" | ||||
|             "version": "==4.0.0" | ||||
|         }, | ||||
|         "click": { | ||||
|             "hashes": [ | ||||
| @ -343,11 +343,11 @@ | ||||
|         }, | ||||
|         "django-storages": { | ||||
|             "hashes": [ | ||||
|                 "sha256:12de8fb2605b9b57bfaf54b075280d7cbb3b3ee1ca4bc9b9add147af87fe3a2c", | ||||
|                 "sha256:652275ab7844538c462b62810276c0244866f345878256a9e0e86f5b1283ae18" | ||||
|                 "sha256:056ec3e9e2b0c6f363913976072ffba2923e79e4859578047da139ba1637497e", | ||||
|                 "sha256:7af56611c62a1c174aab4e862efb7fdd98296dccf76f42135f5b6851fc313c97" | ||||
|             ], | ||||
|             "index": "pypi", | ||||
|             "version": "==1.10.1" | ||||
|             "version": "==1.11" | ||||
|         }, | ||||
|         "djangorestframework": { | ||||
|             "hashes": [ | ||||
| @ -396,10 +396,10 @@ | ||||
|         }, | ||||
|         "google-auth": { | ||||
|             "hashes": [ | ||||
|                 "sha256:5176db85f1e7e837a646cd9cede72c3c404ccf2e3373d9ee14b2db88febad440", | ||||
|                 "sha256:b728625ff5dfce8f9e56a499c8a4eb51443a67f20f6d28b67d5774c310ec4b6b" | ||||
|                 "sha256:0b0e026b412a0ad096e753907559e4bdb180d9ba9f68dd9036164db4fdc4ad2e", | ||||
|                 "sha256:ce752cc51c31f479dbf9928435ef4b07514b20261b021c7383bee4bda646acb8" | ||||
|             ], | ||||
|             "version": "==1.23.0" | ||||
|             "version": "==1.24.0" | ||||
|         }, | ||||
|         "gunicorn": { | ||||
|             "hashes": [ | ||||
| @ -646,26 +646,46 @@ | ||||
|         }, | ||||
|         "msgpack": { | ||||
|             "hashes": [ | ||||
|                 "sha256:002a0d813e1f7b60da599bdf969e632074f9eec1b96cbed8fb0973a63160a408", | ||||
|                 "sha256:25b3bc3190f3d9d965b818123b7752c5dfb953f0d774b454fd206c18fe384fb8", | ||||
|                 "sha256:271b489499a43af001a2e42f42d876bb98ccaa7e20512ff37ca78c8e12e68f84", | ||||
|                 "sha256:39c54fdebf5fa4dda733369012c59e7d085ebdfe35b6cf648f09d16708f1be5d", | ||||
|                 "sha256:4233b7f86c1208190c78a525cd3828ca1623359ef48f78a6fea4b91bb995775a", | ||||
|                 "sha256:5bea44181fc8e18eed1d0cd76e355073f00ce232ff9653a0ae88cb7d9e643322", | ||||
|                 "sha256:5dba6d074fac9b24f29aaf1d2d032306c27f04187651511257e7831733293ec2", | ||||
|                 "sha256:7a22c965588baeb07242cb561b63f309db27a07382825fc98aecaf0827c1538e", | ||||
|                 "sha256:908944e3f038bca67fcfedb7845c4a257c7749bf9818632586b53bcf06ba4b97", | ||||
|                 "sha256:9534d5cc480d4aff720233411a1f765be90885750b07df772380b34c10ecb5c0", | ||||
|                 "sha256:aa5c057eab4f40ec47ea6f5a9825846be2ff6bf34102c560bad5cad5a677c5be", | ||||
|                 "sha256:b3758dfd3423e358bbb18a7cccd1c74228dffa7a697e5be6cb9535de625c0dbf", | ||||
|                 "sha256:c901e8058dd6653307906c5f157f26ed09eb94a850dddd989621098d347926ab", | ||||
|                 "sha256:cec8bf10981ed70998d98431cd814db0ecf3384e6b113366e7f36af71a0fca08", | ||||
|                 "sha256:db685187a415f51d6b937257474ca72199f393dad89534ebbdd7d7a3b000080e", | ||||
|                 "sha256:e35b051077fc2f3ce12e7c6a34cf309680c63a842db3a0616ea6ed25ad20d272", | ||||
|                 "sha256:e7bbdd8e2b277b77782f3ce34734b0dfde6cbe94ddb74de8d733d603c7f9e2b1", | ||||
|                 "sha256:ea41c9219c597f1d2bf6b374d951d310d58684b5de9dc4bd2976db9e1e22c140" | ||||
|                 "sha256:01835e300967e5ad6fdbfc36eafe74df67ff47e16e0d6dee8766630550315903", | ||||
|                 "sha256:03c5554315317d76c25a15569dd52ac6047b105df71e861f24faf9675672b72d", | ||||
|                 "sha256:0968b368a9a9081435bfcb7a57a1e8b75c7bf038ef911b369acd2e038c7f873a", | ||||
|                 "sha256:1d7ab166401f7789bf11262439336c0a01b878f0d602e48f35c35d2e3a555820", | ||||
|                 "sha256:1e8d27bac821f8aa909904a704a67e5e8bc2e42b153415fc3621b7afbc06702b", | ||||
|                 "sha256:1fc9f21da9fd77088ebfd3c9941b044ca3f4a048e85f7ff5727f26bcdbffed61", | ||||
|                 "sha256:20196229acc193939223118c7420838749d5b0cece49cd397739a3a6ffcfe2d1", | ||||
|                 "sha256:2933443313289725f16bd7b99a8c3aa6a2cca1549e661d7407f056a0af80bf7b", | ||||
|                 "sha256:2966b155356fd231fa441131d7301e1596ee38974ad56dc57fd752fdbe2bb63f", | ||||
|                 "sha256:29a6fb3729215b6fcab786ef4f460a5406a5c056f7021191f70ff7712a3f6ba4", | ||||
|                 "sha256:35cbefa7d7bddfb4b0770a1b9ff721cd8dfe9a680947a68457974d5e3e6acc2f", | ||||
|                 "sha256:35ff1ac162a77fb78be360d9f771d36cbf1202e94fc6d70e284ad5db6ab72608", | ||||
|                 "sha256:40dd1ac7420f071e96b3e4a4a7b8e69546a6f8065ff5995dbacf53f86207eb98", | ||||
|                 "sha256:4bea1938e484c9caca9585105f447d6807c496c153b7244fa726b3cc4a68ec9e", | ||||
|                 "sha256:4e58b9f4a99bc3a90859bb006ec4422448a5ce39e5cd6e7498c56de5dcec9c34", | ||||
|                 "sha256:66d47e952856bfcde46d8351380d0b5b928a73112b66bc06d5367dfcc077c06a", | ||||
|                 "sha256:69f6aa503378548ea1e760c11aeb6fc91952bf3634fd806a38a0e47edb507fcd", | ||||
|                 "sha256:7033215267a0e9f60f4a5e4fb2228a932c404f237817caff8dc3115d9e7cd975", | ||||
|                 "sha256:7b50afd767cc053ad92fad39947c3670db27305fd1c49acded44d9d9ac8b56fd", | ||||
|                 "sha256:99ea9e65876546743b2b8bb5bc7adefbb03b9da78a899827467da197a48f790b", | ||||
|                 "sha256:abcc62303ac4d789878d4aac4cdba1bbe2adb478d67be99cd4a6d56ac3a4028f", | ||||
|                 "sha256:b107f9b36665bf7d7c6176a938a361a7aba16aa179d833919448f77287866484", | ||||
|                 "sha256:b5b27923b6c98a2616b7e906a29e4e10e1b4424aea87a0e0d5636327dc6ea315", | ||||
|                 "sha256:bf8eedc7bfbf63cbc9abe58287c32d78780a347835e82c23033c68f11f80bb05", | ||||
|                 "sha256:c144ff4954a6ea40aa603600c8be175349588fc68696092889fa34ab6e055060", | ||||
|                 "sha256:c4e5f96a1d0d916ce7a16decb7499e8923ddef007cf7d68412fb68767766648a", | ||||
|                 "sha256:c60e8b2bf754b8dcc1075c5bee0b177ed9193e7cbd2377faaf507120a948e697", | ||||
|                 "sha256:c82fc6cdba5737eb6ed0c926a30a5d56e7b050297375a16d6c5ad89b576fd979", | ||||
|                 "sha256:ce4ebe2c79411cd5671b20862831880e7850a2de699cff6626f48853fde61ae6", | ||||
|                 "sha256:d113c6b1239c62669ef3063693842605a3edbfebc39a333cf91ba60d314afe6d", | ||||
|                 "sha256:d3cea07ad16919a44e8d1ea67efa5244855cdce807d672f41694acc24d08834e", | ||||
|                 "sha256:d76672602db16e3f44bc1a85c7ee5f15d79e02fcf5bc9d133c2954753be6eddc", | ||||
|                 "sha256:decf2091b75987ca2564e3b742f9614eb7d57e39ff04eaa68af7a3fc5648f7ed", | ||||
|                 "sha256:e13b9007af66a3f62574bc0a13843df0e4402f5ee4b00a02aa1803f01d26b9fb", | ||||
|                 "sha256:e157edf4213dacafb0f862e0b7a3a18448250cec91aa1334f432f49028acc650", | ||||
|                 "sha256:e234ff83628ca3ab345bf97fb36ccbf6d2f1700f5e08868643bf4489edc960f8", | ||||
|                 "sha256:f08d9dd3ce0c5e972dc4653f0fb66d2703941e65356388c13032b578dd718261", | ||||
|                 "sha256:f20d7d4f1f0728560408ba6933154abccf0c20f24642a2404b43d5c23e4119ab" | ||||
|             ], | ||||
|             "version": "==1.0.0" | ||||
|             "version": "==1.0.1" | ||||
|         }, | ||||
|         "oauthlib": { | ||||
|             "hashes": [ | ||||
| @ -676,11 +696,11 @@ | ||||
|         }, | ||||
|         "packaging": { | ||||
|             "hashes": [ | ||||
|                 "sha256:05af3bb85d320377db281cf254ab050e1a7ebcbf5410685a9a407e18a1f81236", | ||||
|                 "sha256:eb41423378682dadb7166144a4926e443093863024de508ca5c9737d6bc08376" | ||||
|                 "sha256:24e0da08660a87484d1602c30bb4902d74816b6985b93de36926f5bc95741858", | ||||
|                 "sha256:78598185a7008a470d64526a8059de9aaa449238f280fc9eb6b13ba6c4109093" | ||||
|             ], | ||||
|             "index": "pypi", | ||||
|             "version": "==20.7" | ||||
|             "version": "==20.8" | ||||
|         }, | ||||
|         "prometheus-client": { | ||||
|             "hashes": [ | ||||
| @ -855,10 +875,10 @@ | ||||
|         }, | ||||
|         "pyopenssl": { | ||||
|             "hashes": [ | ||||
|                 "sha256:898aefbde331ba718570244c3b01dcddb1b31a3b336613436a45e52e27d9a82d", | ||||
|                 "sha256:92f08eccbd73701cf744e8ffd6989aa7842d48cbe3fea8a7c031c5647f590ac5" | ||||
|                 "sha256:4c231c759543ba02560fcd2480c48dcec4dae34c9da7d3747c508227e0624b51", | ||||
|                 "sha256:818ae18e06922c066f777a33f1fca45786d85edfe71cd043de6379337a7f274b" | ||||
|             ], | ||||
|             "version": "==20.0.0" | ||||
|             "version": "==20.0.1" | ||||
|         }, | ||||
|         "pyparsing": { | ||||
|             "hashes": [ | ||||
| @ -930,10 +950,10 @@ | ||||
|         }, | ||||
|         "requests": { | ||||
|             "hashes": [ | ||||
|                 "sha256:7f1a0b932f4a60a1a65caa4263921bb7d9ee911957e0ae4a23a6dd08185ad5f8", | ||||
|                 "sha256:e786fa28d8c9154e6a4de5d46a1d921b8749f8b74e28bde23768e5e16eece998" | ||||
|                 "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804", | ||||
|                 "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e" | ||||
|             ], | ||||
|             "version": "==2.25.0" | ||||
|             "version": "==2.25.1" | ||||
|         }, | ||||
|         "requests-oauthlib": { | ||||
|             "hashes": [ | ||||
| @ -948,7 +968,7 @@ | ||||
|                 "sha256:109ea5a66744dd859bf16fe904b8d8b627adafb9408753161e766a92e7d681fa", | ||||
|                 "sha256:6166864e23d6b5195a5cfed6cd9fed0fe774e226d8f854fcb23b7bbef0350233" | ||||
|             ], | ||||
|             "markers": "python_version >= '3.5'", | ||||
|             "markers": "python_version >= '3.6'", | ||||
|             "version": "==4.6" | ||||
|         }, | ||||
|         "ruamel.yaml": { | ||||
| @ -1073,11 +1093,11 @@ | ||||
|                 "standard" | ||||
|             ], | ||||
|             "hashes": [ | ||||
|                 "sha256:28420526640d800aabe648038f8e2ea8ba2a8bdc363002eecd5dfc57a0f75ab7", | ||||
|                 "sha256:5123606e0f1d15ffbe0f63161c5078f7c28f350c5eb102435671eae58046db0f" | ||||
|                 "sha256:2a7b17f4d9848d6557ccc2274a5f7c97f1daf037d130a0c6918f67cd9bc8cdf5", | ||||
|                 "sha256:6fcce74c00b77d4f4b3ed7ba1b2a370d27133bfdb46f835b7a76dfe0a8c110ae" | ||||
|             ], | ||||
|             "index": "pypi", | ||||
|             "version": "==0.13.0" | ||||
|             "version": "==0.13.1" | ||||
|         }, | ||||
|         "uvloop": { | ||||
|             "hashes": [ | ||||
| @ -1263,11 +1283,11 @@ | ||||
|         }, | ||||
|         "bandit": { | ||||
|             "hashes": [ | ||||
|                 "sha256:2ff3fe35fe3212c0be5fc9c4899bd0108e2b5239c5ff62fb174639e4660fe958", | ||||
|                 "sha256:d02dfe250f4aa2d166c127ad81d192579e2bfcdb8501717c0e2005e35a6bcf60" | ||||
|                 "sha256:216be4d044209fa06cf2a3e51b319769a51be8318140659719aa7a115c35ed07", | ||||
|                 "sha256:8a4c7415254d75df8ff3c3b15cfe9042ecee628a1e40b44c15a98890fbfc2608" | ||||
|             ], | ||||
|             "index": "pypi", | ||||
|             "version": "==1.6.3" | ||||
|             "version": "==1.7.0" | ||||
|         }, | ||||
|         "black": { | ||||
|             "hashes": [ | ||||
| @ -1453,11 +1473,11 @@ | ||||
|         }, | ||||
|         "packaging": { | ||||
|             "hashes": [ | ||||
|                 "sha256:05af3bb85d320377db281cf254ab050e1a7ebcbf5410685a9a407e18a1f81236", | ||||
|                 "sha256:eb41423378682dadb7166144a4926e443093863024de508ca5c9737d6bc08376" | ||||
|                 "sha256:24e0da08660a87484d1602c30bb4902d74816b6985b93de36926f5bc95741858", | ||||
|                 "sha256:78598185a7008a470d64526a8059de9aaa449238f280fc9eb6b13ba6c4109093" | ||||
|             ], | ||||
|             "index": "pypi", | ||||
|             "version": "==20.7" | ||||
|             "version": "==20.8" | ||||
|         }, | ||||
|         "pathspec": { | ||||
|             "hashes": [ | ||||
| @ -1496,10 +1516,10 @@ | ||||
|         }, | ||||
|         "py": { | ||||
|             "hashes": [ | ||||
|                 "sha256:366389d1db726cd2fcfc79732e75410e5fe4d31db13692115529d34069a043c2", | ||||
|                 "sha256:9ca6883ce56b4e8da7e79ac18787889fa5206c79dcc67fb065376cd2fe03f342" | ||||
|                 "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3", | ||||
|                 "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a" | ||||
|             ], | ||||
|             "version": "==1.9.0" | ||||
|             "version": "==1.10.0" | ||||
|         }, | ||||
|         "pycodestyle": { | ||||
|             "hashes": [ | ||||
| @ -1566,11 +1586,11 @@ | ||||
|         }, | ||||
|         "pytest": { | ||||
|             "hashes": [ | ||||
|                 "sha256:4288fed0d9153d9646bfcdf0c0428197dba1ecb27a33bb6e031d002fa88653fe", | ||||
|                 "sha256:c0a7e94a8cdbc5422a51ccdad8e6f1024795939cc89159a0ae7f0b316ad3823e" | ||||
|                 "sha256:1969f797a1a0dbd8ccf0fecc80262312729afea9c17f1d70ebf85c5e76c6f7c8", | ||||
|                 "sha256:66e419b1899bc27346cb2c993e12c5e5e8daba9073c1fbce33b9807abc95c306" | ||||
|             ], | ||||
|             "index": "pypi", | ||||
|             "version": "==6.1.2" | ||||
|             "version": "==6.2.1" | ||||
|         }, | ||||
|         "pytest-django": { | ||||
|             "hashes": [ | ||||
|  | ||||
| @ -1,2 +1,2 @@ | ||||
| """authentik""" | ||||
| __version__ = "0.13.0-rc4" | ||||
| __version__ = "0.13.3-stable" | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| """authentik administration overview""" | ||||
| """authentik administration metrics""" | ||||
| import time | ||||
| from collections import Counter | ||||
| from datetime import timedelta | ||||
| @ -47,7 +47,7 @@ def get_events_per_1h(**filter_kwargs) -> List[Dict[str, int]]: | ||||
| 
 | ||||
| 
 | ||||
| class AdministrationMetricsSerializer(Serializer): | ||||
|     """Overview View""" | ||||
|     """Login Metrics per 1h""" | ||||
| 
 | ||||
|     logins_per_1h = SerializerMethodField() | ||||
|     logins_failed_per_1h = SerializerMethodField() | ||||
| @ -68,12 +68,12 @@ class AdministrationMetricsSerializer(Serializer): | ||||
| 
 | ||||
| 
 | ||||
| class AdministrationMetricsViewSet(ViewSet): | ||||
|     """Return single instance of AdministrationMetricsSerializer""" | ||||
|     """Login Metrics per 1h""" | ||||
| 
 | ||||
|     permission_classes = [IsAdminUser] | ||||
| 
 | ||||
|     @swagger_auto_schema(responses={200: AdministrationMetricsSerializer(many=True)}) | ||||
|     def list(self, request: Request) -> Response: | ||||
|         """Return single instance of AdministrationMetricsSerializer""" | ||||
|         """Login Metrics per 1h""" | ||||
|         serializer = AdministrationMetricsSerializer(True) | ||||
|         return Response(serializer.data) | ||||
| @ -1,79 +0,0 @@ | ||||
| """authentik administration overview""" | ||||
| from django.core.cache import cache | ||||
| from drf_yasg2.utils import swagger_auto_schema | ||||
| from rest_framework.fields import SerializerMethodField | ||||
| from rest_framework.permissions import IsAdminUser | ||||
| from rest_framework.request import Request | ||||
| from rest_framework.response import Response | ||||
| from rest_framework.serializers import Serializer | ||||
| from rest_framework.viewsets import ViewSet | ||||
|  | ||||
| from authentik import __version__ | ||||
| from authentik.admin.tasks import VERSION_CACHE_KEY, update_latest_version | ||||
| from authentik.core.models import Provider | ||||
| from authentik.policies.models import Policy | ||||
| from authentik.root.celery import CELERY_APP | ||||
|  | ||||
|  | ||||
| class AdministrationOverviewSerializer(Serializer): | ||||
|     """Overview View""" | ||||
|  | ||||
|     version = SerializerMethodField() | ||||
|     version_latest = SerializerMethodField() | ||||
|     worker_count = SerializerMethodField() | ||||
|     providers_without_application = SerializerMethodField() | ||||
|     policies_without_binding = SerializerMethodField() | ||||
|     cached_policies = SerializerMethodField() | ||||
|     cached_flows = SerializerMethodField() | ||||
|  | ||||
|     def get_version(self, _) -> str: | ||||
|         """Get current version""" | ||||
|         return __version__ | ||||
|  | ||||
|     def get_version_latest(self, _) -> str: | ||||
|         """Get latest version from cache""" | ||||
|         version_in_cache = cache.get(VERSION_CACHE_KEY) | ||||
|         if not version_in_cache: | ||||
|             update_latest_version.delay() | ||||
|             return __version__ | ||||
|         return version_in_cache | ||||
|  | ||||
|     def get_worker_count(self, _) -> int: | ||||
|         """Ping workers""" | ||||
|         return len(CELERY_APP.control.ping(timeout=0.5)) | ||||
|  | ||||
|     def get_providers_without_application(self, _) -> int: | ||||
|         """Count of providers without application""" | ||||
|         return len(Provider.objects.filter(application=None)) | ||||
|  | ||||
|     def get_policies_without_binding(self, _) -> int: | ||||
|         """Count of policies not bound or use in prompt stages""" | ||||
|         return len( | ||||
|             Policy.objects.filter(bindings__isnull=True, promptstage__isnull=True) | ||||
|         ) | ||||
|  | ||||
|     def get_cached_policies(self, _) -> int: | ||||
|         """Get cached policy count""" | ||||
|         return len(cache.keys("policy_*")) | ||||
|  | ||||
|     def get_cached_flows(self, _) -> int: | ||||
|         """Get cached flow count""" | ||||
|         return len(cache.keys("flow_*")) | ||||
|  | ||||
|     def create(self, request: Request) -> Response: | ||||
|         raise NotImplementedError | ||||
|  | ||||
|     def update(self, request: Request) -> Response: | ||||
|         raise NotImplementedError | ||||
|  | ||||
|  | ||||
| class AdministrationOverviewViewSet(ViewSet): | ||||
|     """Return single instance of AdministrationOverviewSerializer""" | ||||
|  | ||||
|     permission_classes = [IsAdminUser] | ||||
|  | ||||
|     @swagger_auto_schema(responses={200: AdministrationOverviewSerializer(many=True)}) | ||||
|     def list(self, request: Request) -> Response: | ||||
|         """Return single instance of AdministrationOverviewSerializer""" | ||||
|         serializer = AdministrationOverviewSerializer(True) | ||||
|         return Response(serializer.data) | ||||
| @ -66,7 +66,7 @@ class TaskViewSet(ViewSet): | ||||
|                     "successful": True, | ||||
|                 } | ||||
|             ) | ||||
|         except ImportError: | ||||
|         except ImportError:  # pragma: no cover | ||||
|             # if we get an import error, the module path has probably changed | ||||
|             task.delete() | ||||
|             return Response({"successful": False}) | ||||
|  | ||||
							
								
								
									
										60
									
								
								authentik/admin/api/version.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								authentik/admin/api/version.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,60 @@ | ||||
| """authentik administration overview""" | ||||
| from django.core.cache import cache | ||||
| from drf_yasg2.utils import swagger_auto_schema | ||||
| from packaging.version import parse | ||||
| from rest_framework.fields import SerializerMethodField | ||||
| from rest_framework.mixins import ListModelMixin | ||||
| from rest_framework.permissions import IsAdminUser | ||||
| from rest_framework.request import Request | ||||
| from rest_framework.response import Response | ||||
| from rest_framework.serializers import Serializer | ||||
| from rest_framework.viewsets import GenericViewSet | ||||
|  | ||||
| from authentik import __version__ | ||||
| from authentik.admin.tasks import VERSION_CACHE_KEY, update_latest_version | ||||
|  | ||||
|  | ||||
| class VersionSerializer(Serializer): | ||||
|     """Get running and latest version.""" | ||||
|  | ||||
|     version_current = SerializerMethodField() | ||||
|     version_latest = SerializerMethodField() | ||||
|     outdated = SerializerMethodField() | ||||
|  | ||||
|     def get_version_current(self, _) -> str: | ||||
|         """Get current version""" | ||||
|         return __version__ | ||||
|  | ||||
|     def get_version_latest(self, _) -> str: | ||||
|         """Get latest version from cache""" | ||||
|         version_in_cache = cache.get(VERSION_CACHE_KEY) | ||||
|         if not version_in_cache:  # pragma: no cover | ||||
|             update_latest_version.delay() | ||||
|             return __version__ | ||||
|         return version_in_cache | ||||
|  | ||||
|     def get_outdated(self, instance) -> bool: | ||||
|         """Check if we're running the latest version""" | ||||
|         return parse(self.get_version_current(instance)) < parse( | ||||
|             self.get_version_latest(instance) | ||||
|         ) | ||||
|  | ||||
|     def create(self, request: Request) -> Response: | ||||
|         raise NotImplementedError | ||||
|  | ||||
|     def update(self, request: Request) -> Response: | ||||
|         raise NotImplementedError | ||||
|  | ||||
|  | ||||
| class VersionViewSet(ListModelMixin, GenericViewSet): | ||||
|     """Get running and latest version.""" | ||||
|  | ||||
|     permission_classes = [IsAdminUser] | ||||
|  | ||||
|     def get_queryset(self): | ||||
|         return None | ||||
|  | ||||
|     @swagger_auto_schema(responses={200: VersionSerializer(many=True)}) | ||||
|     def list(self, request: Request) -> Response: | ||||
|         """Get running and latest version.""" | ||||
|         return Response(VersionSerializer(True).data) | ||||
							
								
								
									
										25
									
								
								authentik/admin/api/workers.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								authentik/admin/api/workers.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | ||||
| """authentik administration overview""" | ||||
| from rest_framework.mixins import ListModelMixin | ||||
| from rest_framework.permissions import IsAdminUser | ||||
| from rest_framework.request import Request | ||||
| from rest_framework.response import Response | ||||
| from rest_framework.serializers import Serializer | ||||
| from rest_framework.viewsets import GenericViewSet | ||||
|  | ||||
| from authentik.root.celery import CELERY_APP | ||||
|  | ||||
|  | ||||
| class WorkerViewSet(ListModelMixin, GenericViewSet): | ||||
|     """Get currently connected worker count.""" | ||||
|  | ||||
|     serializer_class = Serializer | ||||
|     permission_classes = [IsAdminUser] | ||||
|  | ||||
|     def get_queryset(self): | ||||
|         return None | ||||
|  | ||||
|     def list(self, request: Request) -> Response: | ||||
|         """Get currently connected worker count.""" | ||||
|         return Response( | ||||
|             {"pagination": {"count": len(CELERY_APP.control.ping(timeout=0.5))}} | ||||
|         ) | ||||
| @ -1,230 +0,0 @@ | ||||
| {% extends "administration/base.html" %} | ||||
|  | ||||
| {% load i18n %} | ||||
| {% load static %} | ||||
|  | ||||
| {% block content %} | ||||
| <section class="pf-c-page__main-section pf-m-light"> | ||||
|     <div class="pf-c-content"> | ||||
|         <h1>{% trans 'System Overview' %}</h1> | ||||
|     </div> | ||||
| </section> | ||||
| <section class="pf-c-page__main-section"> | ||||
|     <div class="pf-l-gallery pf-m-gutter"> | ||||
|         <div class="pf-c-card pf-c-card-aggregate pf-l-gallery__item pf-m-4-col" style="grid-column-end: span 3;grid-row-end: span 2;"> | ||||
|             <div class="pf-c-card__header"> | ||||
|                 <div class="pf-c-card__header-main"> | ||||
|                     <i class="pf-icon pf-icon-server"></i> {% trans 'Logins over the last 24 hours' %} | ||||
|                 </div> | ||||
|             </div> | ||||
|             <div class="pf-c-card__body"> | ||||
|                 <ak-admin-logins-chart url="{% url 'authentik_api:admin_metrics-list' %}"></ak-admin-logins-chart> | ||||
|             </div> | ||||
|         </div> | ||||
|         <div class="pf-c-card pf-c-card-aggregate pf-l-gallery__item pf-m-4-col" style="grid-column-end: span 2;grid-row-end: span 3;"> | ||||
|             <div class="pf-c-card__header"> | ||||
|                 <div class="pf-c-card__header-main"> | ||||
|                     <i class="pf-icon pf-icon-server"></i> {% trans 'Apps with most usage' %} | ||||
|                 </div> | ||||
|             </div> | ||||
|             <div class="pf-c-card__body"> | ||||
|                 <table class="pf-c-table pf-m-compact" role="grid"> | ||||
|                     <thead> | ||||
|                         <tr role="row"> | ||||
|                             <th role="columnheader" scope="col">{% trans 'Application' %}</th> | ||||
|                             <th role="columnheader" scope="col">{% trans 'Logins' %}</th> | ||||
|                             <th role="columnheader" scope="col"></th> | ||||
|                         </tr> | ||||
|                     </thead> | ||||
|                     <tbody role="rowgroup"> | ||||
|                         {% for app in most_used_applications %} | ||||
|                         <tr role="row"> | ||||
|                             <td role="cell"> | ||||
|                                 {{ app.application.name }} | ||||
|                             </td> | ||||
|                             <td role="cell"> | ||||
|                                 {{ app.total_logins }} | ||||
|                             </td> | ||||
|                             <td role="cell"> | ||||
|                                 <progress value="{{ app.total_logins }}" max="{{ most_used_applications.0.total_logins }}"></progress> | ||||
|                             </td> | ||||
|                         </tr> | ||||
|                         {% endfor %} | ||||
|                     </tbody> | ||||
|                 </table> | ||||
|             </div> | ||||
|         </div> | ||||
|  | ||||
|         <div class="pf-c-card pf-c-card-aggregate pf-l-gallery__item pf-m-compact"> | ||||
|             <div class="pf-c-card__header pf-l-flex pf-m-justify-content-space-between"> | ||||
|                 <div class="pf-c-card__header-main"> | ||||
|                     <i class="pf-icon pf-icon-plugged"></i> {% trans 'Providers' %} | ||||
|                 </div> | ||||
|                 <a href="{% url 'authentik_admin:providers' %}"> | ||||
|                     <i class="fa fa-external-link-alt"> </i> | ||||
|                 </a> | ||||
|             </div> | ||||
|             <div class="pf-c-card__body"> | ||||
|                 {% if providers_without_application.exists %} | ||||
|                 <p class="ak-aggregate-card"> | ||||
|                     <i class="fa fa-exclamation-triangle"></i> {{ provider_count }} | ||||
|                 </p> | ||||
|                 <p>{% trans 'Warning: At least one Provider has no application assigned.' %}</p> | ||||
|                 {% else %} | ||||
|                 <p class="ak-aggregate-card"> | ||||
|                     <i class="fa fa-check-circle"></i> {{ provider_count }} | ||||
|                 </p> | ||||
|                 {% endif %} | ||||
|             </div> | ||||
|         </div> | ||||
|  | ||||
|         <div class="pf-c-card pf-c-card-aggregate pf-l-gallery__item pf-m-compact"> | ||||
|             <div class="pf-c-card__header pf-l-flex pf-m-justify-content-space-between"> | ||||
|                 <div class="pf-c-card__header-main"> | ||||
|                     <i class="pf-icon pf-icon-infrastructure"></i> {% trans 'Policies' %} | ||||
|                 </div> | ||||
|                 <a href="{% url 'authentik_admin:policies' %}"> | ||||
|                     <i class="fa fa-external-link-alt"> </i> | ||||
|                 </a> | ||||
|             </div> | ||||
|             <div class="pf-c-card__body"> | ||||
|                 {% if policies_without_binding %} | ||||
|                 <p class="ak-aggregate-card"> | ||||
|                     <i class="fa fa-exclamation-triangle"></i> {{ policy_count }} | ||||
|                 </p> | ||||
|                 <p>{% trans 'Policies without binding exist.' %}</p> | ||||
|                 {% else %} | ||||
|                 <p class="ak-aggregate-card"> | ||||
|                     <i class="fa fa-check-circle"></i> {{ policy_count }} | ||||
|                 </p> | ||||
|                 {% endif %} | ||||
|             </div> | ||||
|         </div> | ||||
|  | ||||
|         <div class="pf-c-card pf-c-card-aggregate pf-l-gallery__item pf-m-compact"> | ||||
|             <div class="pf-c-card__header pf-l-flex pf-m-justify-content-space-between"> | ||||
|                 <div class="pf-c-card__header-main"> | ||||
|                     <i class="pf-icon pf-icon-user"></i> {% trans 'Users' %} | ||||
|                 </div> | ||||
|                 <a href="{% url 'authentik_admin:users' %}"> | ||||
|                     <i class="fa fa-external-link-alt"> </i> | ||||
|                 </a> | ||||
|             </div> | ||||
|             <div class="pf-c-card__body"> | ||||
|                 <p class="ak-aggregate-card"> | ||||
|                     <i class="fa fa-check-circle"></i> {{ user_count }} | ||||
|                 </p> | ||||
|             </div> | ||||
|         </div> | ||||
|  | ||||
|         <div class="pf-c-card pf-c-card-aggregate pf-l-gallery__item pf-m-compact"> | ||||
|             <div class="pf-c-card__header pf-l-flex pf-m-justify-content-space-between"> | ||||
|                 <div class="pf-c-card__header-main"> | ||||
|                     <i class="pf-icon pf-icon-bundle"></i> {% trans 'Version' %} | ||||
|                 </div> | ||||
|                 <a href="https://github.com/BeryJu/authentik/releases" target="_blank"> | ||||
|                     <i class="fa fa-external-link-alt"> </i> | ||||
|                 </a> | ||||
|             </div> | ||||
|             <div class="pf-c-card__body"> | ||||
|                 <p class="ak-aggregate-card"> | ||||
|                     {% if version >= version_latest %} | ||||
|                     <i class="fa fa-check-circle"></i> {{ version }} | ||||
|                     {% else %} | ||||
|                     <i class="fa fa-exclamation-triangle"></i> {{ version }} | ||||
|                     {% endif %} | ||||
|                 </p> | ||||
|                 {% if version >= version_latest %} | ||||
|                     {% blocktrans %} | ||||
|                     Up-to-date! | ||||
|                     {% endblocktrans %} | ||||
|                 {% else %} | ||||
|                     {% blocktrans with latest=version_latest %} | ||||
|                     {{ latest }} is available! | ||||
|                     {% endblocktrans %} | ||||
|                 {% endif %} | ||||
|             </div> | ||||
|         </div> | ||||
|  | ||||
|         <div class="pf-c-card pf-c-card-aggregate pf-l-gallery__item pf-m-compact"> | ||||
|             <div class="pf-c-card__header"> | ||||
|                 <div class="pf-c-card__header-main"> | ||||
|                     <i class="pf-icon pf-icon-server"></i> {% trans 'Workers' %} | ||||
|                 </div> | ||||
|             </div> | ||||
|             <fetch-fill-slot class="pf-c-card__body" url="{% url 'authentik_api:admin_overview-list' %}" key="worker_count"> | ||||
|                 <div slot="value < 1"> | ||||
|                     <p class="ak-aggregate-card"> | ||||
|                         <i class="fa fa-exclamation-triangle"></i> <span data-value></span> | ||||
|                     </p> | ||||
|                     <p>{% trans 'No workers connected.' %}</p> | ||||
|                 </div> | ||||
|                 <div slot="value >= 1"> | ||||
|                     <p class="ak-aggregate-card"> | ||||
|                         <i class="fa fa-check-circle"></i> <span data-value></span> | ||||
|                     </p> | ||||
|                 </div> | ||||
|                 <div> | ||||
|                     <span class="pf-c-spinner" role="progressbar" aria-valuetext="Loading..."> | ||||
|                         <span class="pf-c-spinner__clipper"></span> | ||||
|                         <span class="pf-c-spinner__lead-ball"></span> | ||||
|                         <span class="pf-c-spinner__tail-ball"></span> | ||||
|                     </span> | ||||
|                 </div> | ||||
|             </fetch-fill-slot> | ||||
|         </div> | ||||
|  | ||||
|         <div class="pf-c-card pf-c-card-aggregate pf-l-gallery__item pf-m-compact"> | ||||
|             <div class="pf-c-card__header pf-l-flex pf-m-justify-content-space-between"> | ||||
|                 <div class="pf-c-card__header-main"> | ||||
|                     <i class="pf-icon pf-icon-server"></i> {% trans 'Cached Policies' %} | ||||
|                 </div> | ||||
|                 <ak-modal-button href="{% url 'authentik_admin:overview-clear-policy-cache' %}"> | ||||
|                     <a slot="trigger"> | ||||
|                         <i class="fa fa-trash"> </i> | ||||
|                     </a> | ||||
|                     <div slot="modal"></div> | ||||
|                 </ak-modal-button> | ||||
|             </div> | ||||
|             <div class="pf-c-card__body"> | ||||
|                 {% if cached_policies < 1 %} | ||||
|                 <p class="ak-aggregate-card"> | ||||
|                     <i class="fa fa-exclamation-triangle"></i> {{ cached_policies }} | ||||
|                 </p> | ||||
|                 <p>{% trans 'No policies cached. Users may experience slow response times.' %}</p> | ||||
|                 {% else %} | ||||
|                 <p class="ak-aggregate-card"> | ||||
|                     <i class="fa fa-check-circle"></i> {{ cached_policies }} | ||||
|                 </p> | ||||
|                 {% endif %} | ||||
|             </div> | ||||
|         </div> | ||||
|  | ||||
|         <div class="pf-c-card pf-c-card-aggregate pf-l-gallery__item pf-m-compact"> | ||||
|             <div class="pf-c-card__header pf-l-flex pf-m-justify-content-space-between"> | ||||
|                 <div class="pf-c-card__header-main"> | ||||
|                     <i class="pf-icon pf-icon-server"></i> {% trans 'Cached Flows' %} | ||||
|                 </div> | ||||
|                 <ak-modal-button href="{% url 'authentik_admin:overview-clear-flow-cache' %}"> | ||||
|                     <a slot="trigger"> | ||||
|                         <i class="fa fa-trash"> </i> | ||||
|                     </a> | ||||
|                     <div slot="modal"></div> | ||||
|                 </ak-modal-button> | ||||
|             </div> | ||||
|             <div class="pf-c-card__body"> | ||||
|                 {% if cached_flows < 1 %} | ||||
|                 <p class="ak-aggregate-card"> | ||||
|                     <span class="fa fa-exclamation-triangle"></span> {{ cached_flows }} | ||||
|                 </p> | ||||
|                 <p>{% trans 'No flows cached.' %}</p> | ||||
|                 {% else %} | ||||
|                 <p class="ak-aggregate-card"> | ||||
|                     <i class="fa fa-check-circle"></i> {{ cached_flows }} | ||||
|                 </p> | ||||
|                 {% endif %} | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
| </section> | ||||
| {% endblock %} | ||||
| @ -6,6 +6,7 @@ from django.test import TestCase | ||||
|  | ||||
| from authentik import __version__ | ||||
| from authentik.core.models import Group, User | ||||
| from authentik.core.tasks import clean_expired_models | ||||
|  | ||||
|  | ||||
| class TestAdminAPI(TestCase): | ||||
| @ -19,19 +20,54 @@ class TestAdminAPI(TestCase): | ||||
|         self.group.save() | ||||
|         self.client.force_login(self.user) | ||||
|  | ||||
|     def test_overview(self): | ||||
|         """Test Overview API""" | ||||
|         response = self.client.get(reverse("authentik_api:admin_overview-list")) | ||||
|     def test_tasks(self): | ||||
|         """Test Task API""" | ||||
|         clean_expired_models.delay() | ||||
|         response = self.client.get(reverse("authentik_api:admin_system_tasks-list")) | ||||
|         self.assertEqual(response.status_code, 200) | ||||
|         body = loads(response.content) | ||||
|         self.assertEqual(body["version"], __version__) | ||||
|         self.assertTrue( | ||||
|             any([task["task_name"] == "clean_expired_models" for task in body]) | ||||
|         ) | ||||
|  | ||||
|     def test_tasks_retry(self): | ||||
|         """Test Task API (retry)""" | ||||
|         clean_expired_models.delay() | ||||
|         response = self.client.post( | ||||
|             reverse( | ||||
|                 "authentik_api:admin_system_tasks-retry", | ||||
|                 kwargs={"pk": "clean_expired_models"}, | ||||
|             ) | ||||
|         ) | ||||
|         self.assertEqual(response.status_code, 200) | ||||
|         body = loads(response.content) | ||||
|         self.assertTrue(body["successful"]) | ||||
|  | ||||
|     def test_tasks_retry_404(self): | ||||
|         """Test Task API (retry, 404)""" | ||||
|         response = self.client.post( | ||||
|             reverse( | ||||
|                 "authentik_api:admin_system_tasks-retry", | ||||
|                 kwargs={"pk": "qwerqewrqrqewrqewr"}, | ||||
|             ) | ||||
|         ) | ||||
|         self.assertEqual(response.status_code, 404) | ||||
|  | ||||
|     def test_version(self): | ||||
|         """Test Version API""" | ||||
|         response = self.client.get(reverse("authentik_api:admin_version-list")) | ||||
|         self.assertEqual(response.status_code, 200) | ||||
|         body = loads(response.content) | ||||
|         self.assertEqual(body["version_current"], __version__) | ||||
|  | ||||
|     def test_workers(self): | ||||
|         """Test Workers API""" | ||||
|         response = self.client.get(reverse("authentik_api:admin_workers-list")) | ||||
|         self.assertEqual(response.status_code, 200) | ||||
|         body = loads(response.content) | ||||
|         self.assertEqual(body["pagination"]["count"], 0) | ||||
|  | ||||
|     def test_metrics(self): | ||||
|         """Test metrics API""" | ||||
|         response = self.client.get(reverse("authentik_api:admin_metrics-list")) | ||||
|         self.assertEqual(response.status_code, 200) | ||||
|  | ||||
|     def test_tasks(self): | ||||
|         """Test tasks metrics API""" | ||||
|         response = self.client.get(reverse("authentik_api:admin_system_tasks-list")) | ||||
|         self.assertEqual(response.status_code, 200) | ||||
|  | ||||
| @ -34,7 +34,6 @@ urlpatterns = [ | ||||
|         overview.PolicyCacheClearView.as_view(), | ||||
|         name="overview-clear-policy-cache", | ||||
|     ), | ||||
|     path("overview/", overview.AdministrationOverviewView.as_view(), name="overview"), | ||||
|     # Applications | ||||
|     path( | ||||
|         "applications/", applications.ApplicationListView.as_view(), name="applications" | ||||
|  | ||||
| @ -1,65 +1,25 @@ | ||||
| """authentik administration overview""" | ||||
| from typing import Union | ||||
|  | ||||
| from django.conf import settings | ||||
| from django.contrib.messages.views import SuccessMessageMixin | ||||
| from django.core.cache import cache | ||||
| from django.http.request import HttpRequest | ||||
| from django.http.response import HttpResponse | ||||
| from django.urls import reverse_lazy | ||||
| from django.utils.translation import gettext as _ | ||||
| from django.views.generic import FormView, TemplateView | ||||
| from packaging.version import LegacyVersion, Version, parse | ||||
| from django.views.generic import FormView | ||||
| from structlog import get_logger | ||||
|  | ||||
| from authentik import __version__ | ||||
| from authentik.admin.forms.overview import FlowCacheClearForm, PolicyCacheClearForm | ||||
| from authentik.admin.mixins import AdminRequiredMixin | ||||
| from authentik.admin.tasks import VERSION_CACHE_KEY, update_latest_version | ||||
| from authentik.core.models import Provider, User | ||||
| from authentik.policies.models import Policy | ||||
|  | ||||
| LOGGER = get_logger() | ||||
|  | ||||
|  | ||||
| class AdministrationOverviewView(AdminRequiredMixin, TemplateView): | ||||
|     """Overview View""" | ||||
|  | ||||
|     template_name = "administration/overview.html" | ||||
|  | ||||
|     def get_latest_version(self) -> Union[LegacyVersion, Version]: | ||||
|         """Get latest version from cache""" | ||||
|         version_in_cache = cache.get(VERSION_CACHE_KEY) | ||||
|         if not version_in_cache: | ||||
|             if not settings.DEBUG: | ||||
|                 update_latest_version.delay() | ||||
|             return parse(__version__) | ||||
|         return parse(version_in_cache) | ||||
|  | ||||
|     def get_context_data(self, **kwargs): | ||||
|         kwargs["policy_count"] = len(Policy.objects.all()) | ||||
|         kwargs["user_count"] = len(User.objects.all()) - 1  # Remove anonymous user | ||||
|         kwargs["provider_count"] = len(Provider.objects.all()) | ||||
|         kwargs["version"] = parse(__version__) | ||||
|         kwargs["version_latest"] = self.get_latest_version() | ||||
|         kwargs["providers_without_application"] = Provider.objects.filter( | ||||
|             application=None | ||||
|         ) | ||||
|         kwargs["policies_without_binding"] = len( | ||||
|             Policy.objects.filter(bindings__isnull=True, promptstage__isnull=True) | ||||
|         ) | ||||
|         kwargs["cached_policies"] = len(cache.keys("policy_*")) | ||||
|         kwargs["cached_flows"] = len(cache.keys("flow_*")) | ||||
|         return super().get_context_data(**kwargs) | ||||
|  | ||||
|  | ||||
| class PolicyCacheClearView(AdminRequiredMixin, SuccessMessageMixin, FormView): | ||||
|     """View to clear Policy cache""" | ||||
|  | ||||
|     form_class = PolicyCacheClearForm | ||||
|  | ||||
|     template_name = "generic/form_non_model.html" | ||||
|     success_url = reverse_lazy("authentik_admin:overview") | ||||
|     success_url = "/" | ||||
|     success_message = _("Successfully cleared Policy cache") | ||||
|  | ||||
|     def post(self, request: HttpRequest, *args, **kwargs) -> HttpResponse: | ||||
| @ -75,7 +35,7 @@ class FlowCacheClearView(AdminRequiredMixin, SuccessMessageMixin, FormView): | ||||
|     form_class = FlowCacheClearForm | ||||
|  | ||||
|     template_name = "generic/form_non_model.html" | ||||
|     success_url = reverse_lazy("authentik_admin:overview") | ||||
|     success_url = "/" | ||||
|     success_message = _("Successfully cleared Flow cache") | ||||
|  | ||||
|     def post(self, request: HttpRequest, *args, **kwargs) -> HttpResponse: | ||||
|  | ||||
| @ -5,9 +5,10 @@ from drf_yasg2.views import get_schema_view | ||||
| from rest_framework import routers | ||||
| from rest_framework.permissions import AllowAny | ||||
|  | ||||
| from authentik.admin.api.overview import AdministrationOverviewViewSet | ||||
| from authentik.admin.api.overview_metrics import AdministrationMetricsViewSet | ||||
| from authentik.admin.api.metrics import AdministrationMetricsViewSet | ||||
| from authentik.admin.api.tasks import TaskViewSet | ||||
| from authentik.admin.api.version import VersionViewSet | ||||
| from authentik.admin.api.workers import WorkerViewSet | ||||
| from authentik.api.v2.config import ConfigsViewSet | ||||
| from authentik.api.v2.messages import MessagesViewSet | ||||
| from authentik.audit.api import EventViewSet | ||||
| @ -19,13 +20,22 @@ from authentik.core.api.sources import SourceViewSet | ||||
| from authentik.core.api.tokens import TokenViewSet | ||||
| from authentik.core.api.users import UserViewSet | ||||
| from authentik.crypto.api import CertificateKeyPairViewSet | ||||
| from authentik.flows.api import FlowStageBindingViewSet, FlowViewSet, StageViewSet | ||||
| from authentik.flows.api import ( | ||||
|     FlowCacheViewSet, | ||||
|     FlowStageBindingViewSet, | ||||
|     FlowViewSet, | ||||
|     StageViewSet, | ||||
| ) | ||||
| from authentik.outposts.api import ( | ||||
|     DockerServiceConnectionViewSet, | ||||
|     KubernetesServiceConnectionViewSet, | ||||
|     OutpostViewSet, | ||||
| ) | ||||
| from authentik.policies.api import PolicyBindingViewSet, PolicyViewSet | ||||
| from authentik.policies.api import ( | ||||
|     PolicyBindingViewSet, | ||||
|     PolicyCacheViewSet, | ||||
|     PolicyViewSet, | ||||
| ) | ||||
| from authentik.policies.dummy.api import DummyPolicyViewSet | ||||
| from authentik.policies.expiry.api import PasswordExpiryPolicyViewSet | ||||
| from authentik.policies.expression.api import ExpressionPolicyViewSet | ||||
| @ -63,9 +73,8 @@ router = routers.DefaultRouter() | ||||
| router.register("root/messages", MessagesViewSet, basename="messages") | ||||
| router.register("root/config", ConfigsViewSet, basename="configs") | ||||
|  | ||||
| router.register( | ||||
|     "admin/overview", AdministrationOverviewViewSet, basename="admin_overview" | ||||
| ) | ||||
| router.register("admin/version", VersionViewSet, basename="admin_version") | ||||
| router.register("admin/workers", WorkerViewSet, basename="admin_workers") | ||||
| router.register("admin/metrics", AdministrationMetricsViewSet, basename="admin_metrics") | ||||
| router.register("admin/system_tasks", TaskViewSet, basename="admin_system_tasks") | ||||
|  | ||||
| @ -82,6 +91,7 @@ router.register( | ||||
| router.register("outposts/proxy", ProxyOutpostConfigViewSet) | ||||
|  | ||||
| router.register("flows/instances", FlowViewSet) | ||||
| router.register("flows/cached", FlowCacheViewSet, basename="flows_cache") | ||||
| router.register("flows/bindings", FlowStageBindingViewSet) | ||||
|  | ||||
| router.register("crypto/certificatekeypairs", CertificateKeyPairViewSet) | ||||
| @ -94,6 +104,7 @@ router.register("sources/saml", SAMLSourceViewSet) | ||||
| router.register("sources/oauth", OAuthSourceViewSet) | ||||
|  | ||||
| router.register("policies/all", PolicyViewSet) | ||||
| router.register("policies/cached", PolicyCacheViewSet, basename="policies_cache") | ||||
| router.register("policies/bindings", PolicyBindingViewSet) | ||||
| router.register("policies/expression", ExpressionPolicyViewSet) | ||||
| router.register("policies/group_membership", GroupMembershipPolicyViewSet) | ||||
|  | ||||
| @ -11,7 +11,7 @@ from rest_framework.serializers import ModelSerializer | ||||
| from rest_framework.viewsets import ModelViewSet | ||||
| from rest_framework_guardian.filters import ObjectPermissionsFilter | ||||
|  | ||||
| from authentik.admin.api.overview_metrics import get_events_per_1h | ||||
| from authentik.admin.api.metrics import get_events_per_1h | ||||
| from authentik.audit.models import EventAction | ||||
| from authentik.core.models import Application | ||||
| from authentik.policies.engine import PolicyEngine | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| """Provider API Views""" | ||||
| from rest_framework.serializers import ModelSerializer, SerializerMethodField | ||||
| from rest_framework.viewsets import ReadOnlyModelViewSet | ||||
| from rest_framework.viewsets import ModelViewSet | ||||
|  | ||||
| from authentik.core.models import Provider | ||||
|  | ||||
| @ -14,17 +14,33 @@ class ProviderSerializer(ModelSerializer): | ||||
|         """Get object type so that we know which API Endpoint to use to get the full object""" | ||||
|         return obj._meta.object_name.lower().replace("provider", "") | ||||
|  | ||||
|     def to_representation(self, instance: Provider): | ||||
|         # pyright: reportGeneralTypeIssues=false | ||||
|         if instance.__class__ == Provider: | ||||
|             return super().to_representation(instance) | ||||
|         return instance.serializer(instance=instance).data | ||||
|  | ||||
|     class Meta: | ||||
|  | ||||
|         model = Provider | ||||
|         fields = ["pk", "name", "authorization_flow", "property_mappings", "__type__"] | ||||
|         fields = [ | ||||
|             "pk", | ||||
|             "name", | ||||
|             "application", | ||||
|             "authorization_flow", | ||||
|             "property_mappings", | ||||
|             "__type__", | ||||
|         ] | ||||
|  | ||||
|  | ||||
| class ProviderViewSet(ReadOnlyModelViewSet): | ||||
| class ProviderViewSet(ModelViewSet): | ||||
|     """Provider Viewset""" | ||||
|  | ||||
|     queryset = Provider.objects.all() | ||||
|     serializer_class = ProviderSerializer | ||||
|     filterset_fields = { | ||||
|         "application": ["isnull"], | ||||
|     } | ||||
|  | ||||
|     def get_queryset(self): | ||||
|         return Provider.objects.select_subclasses() | ||||
|  | ||||
| @ -14,6 +14,7 @@ from django.utils.timezone import now | ||||
| from django.utils.translation import gettext_lazy as _ | ||||
| from guardian.mixins import GuardianUserMixin | ||||
| from model_utils.managers import InheritanceManager | ||||
| from rest_framework.serializers import Serializer | ||||
| from structlog import get_logger | ||||
|  | ||||
| from authentik.core.exceptions import PropertyMappingExpressionException | ||||
| @ -127,7 +128,7 @@ class User(GuardianUserMixin, AbstractUser): | ||||
|         verbose_name_plural = _("Users") | ||||
|  | ||||
|  | ||||
| class Provider(models.Model): | ||||
| class Provider(SerializerModel): | ||||
|     """Application-independent Provider instance. For example SAML2 Remote, OAuth2 Application""" | ||||
|  | ||||
|     name = models.TextField() | ||||
| @ -156,6 +157,11 @@ class Provider(models.Model): | ||||
|         """Return Form class used to edit this object""" | ||||
|         raise NotImplementedError | ||||
|  | ||||
|     @property | ||||
|     def serializer(self) -> Type[Serializer]: | ||||
|         """Get serializer for this model""" | ||||
|         raise NotImplementedError | ||||
|  | ||||
|     def __str__(self): | ||||
|         return self.name | ||||
|  | ||||
|  | ||||
| @ -3,6 +3,15 @@ | ||||
| {% load i18n %} | ||||
| {% load authentik_utils %} | ||||
|  | ||||
| {% block head %} | ||||
| {{ block.super }} | ||||
| <style> | ||||
|     .pf-c-empty-state { | ||||
|         height: 100vh; | ||||
|     } | ||||
| </style> | ||||
| {% endblock %} | ||||
|  | ||||
| {% block body %} | ||||
| <section class="pf-c-page__main-section pf-m-no-padding-mobile pf-m-xl"> | ||||
|     <div class="pf-c-empty-state"> | ||||
|  | ||||
| @ -1,7 +1,14 @@ | ||||
| """Flow API Views""" | ||||
| from django.core.cache import cache | ||||
| from rest_framework.serializers import ModelSerializer, SerializerMethodField | ||||
| from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet | ||||
| from rest_framework.mixins import ListModelMixin | ||||
| from rest_framework.request import Request | ||||
| from rest_framework.response import Response | ||||
| from rest_framework.serializers import ( | ||||
|     ModelSerializer, | ||||
|     Serializer, | ||||
|     SerializerMethodField, | ||||
| ) | ||||
| from rest_framework.viewsets import GenericViewSet, ModelViewSet, ReadOnlyModelViewSet | ||||
|  | ||||
| from authentik.flows.models import Flow, FlowStageBinding, Stage | ||||
| from authentik.flows.planner import cache_key | ||||
| @ -98,3 +105,14 @@ class FlowStageBindingViewSet(ModelViewSet): | ||||
|     queryset = FlowStageBinding.objects.all() | ||||
|     serializer_class = FlowStageBindingSerializer | ||||
|     filterset_fields = "__all__" | ||||
|  | ||||
|  | ||||
| class FlowCacheViewSet(ListModelMixin, GenericViewSet): | ||||
|     """Info about cached flows""" | ||||
|  | ||||
|     queryset = Flow.objects.none() | ||||
|     serializer_class = Serializer | ||||
|  | ||||
|     def list(self, request: Request) -> Response: | ||||
|         """Info about cached flows""" | ||||
|         return Response(data={"pagination": {"count": len(cache.keys("flow_*"))}}) | ||||
|  | ||||
| @ -19,6 +19,7 @@ LOGGER = get_logger() | ||||
|  | ||||
| PLAN_CONTEXT_PENDING_USER = "pending_user" | ||||
| PLAN_CONTEXT_SSO = "is_sso" | ||||
| PLAN_CONTEXT_REDIRECT = "redirect" | ||||
| PLAN_CONTEXT_APPLICATION = "application" | ||||
|  | ||||
|  | ||||
|  | ||||
| @ -8,7 +8,7 @@ from django.test.client import RequestFactory | ||||
| from django.utils.encoding import force_str | ||||
|  | ||||
| from authentik.core.models import User | ||||
| from authentik.flows.exceptions import EmptyFlowException, FlowNonApplicableException | ||||
| from authentik.flows.exceptions import FlowNonApplicableException | ||||
| from authentik.flows.markers import ReevaluateMarker, StageMarker | ||||
| from authentik.flows.models import Flow, FlowDesignation, FlowStageBinding | ||||
| from authentik.flows.planner import FlowPlan, FlowPlanner | ||||
| @ -40,6 +40,10 @@ class TestFlowExecutor(TestCase): | ||||
|     def setUp(self): | ||||
|         self.request_factory = RequestFactory() | ||||
|  | ||||
|     @patch( | ||||
|         "authentik.flows.views.to_stage_response", | ||||
|         TO_STAGE_RESPONSE_MOCK, | ||||
|     ) | ||||
|     def test_existing_plan_diff_flow(self): | ||||
|         """Check that a plan for a different flow cancels the current plan""" | ||||
|         flow = Flow.objects.create( | ||||
| @ -62,7 +66,7 @@ class TestFlowExecutor(TestCase): | ||||
|                     "authentik_flows:flow-executor", kwargs={"flow_slug": flow.slug} | ||||
|                 ), | ||||
|             ) | ||||
|             self.assertEqual(response.status_code, 200) | ||||
|             self.assertEqual(response.status_code, 302) | ||||
|             self.assertEqual(cancel_mock.call_count, 2) | ||||
|  | ||||
|     @patch( | ||||
| @ -105,10 +109,13 @@ class TestFlowExecutor(TestCase): | ||||
|         response = self.client.get( | ||||
|             reverse("authentik_flows:flow-executor", kwargs={"flow_slug": flow.slug}), | ||||
|         ) | ||||
|         self.assertEqual(response.status_code, 200) | ||||
|         self.assertIsInstance(response, AccessDeniedResponse) | ||||
|         self.assertInHTML(EmptyFlowException.__doc__, response.rendered_content) | ||||
|         self.assertEqual(response.status_code, 302) | ||||
|         self.assertEqual(response.url, reverse("authentik_core:shell")) | ||||
|  | ||||
|     @patch( | ||||
|         "authentik.flows.views.to_stage_response", | ||||
|         TO_STAGE_RESPONSE_MOCK, | ||||
|     ) | ||||
|     def test_invalid_flow_redirect(self): | ||||
|         """Tests that an invalid flow still redirects""" | ||||
|         flow = Flow.objects.create( | ||||
| @ -121,11 +128,8 @@ class TestFlowExecutor(TestCase): | ||||
|         dest = "/unique-string" | ||||
|         url = reverse("authentik_flows:flow-executor", kwargs={"flow_slug": flow.slug}) | ||||
|         response = self.client.get(url + f"?{NEXT_ARG_NAME}={dest}") | ||||
|         self.assertEqual(response.status_code, 200) | ||||
|         self.assertJSONEqual( | ||||
|             force_str(response.content), | ||||
|             {"type": "redirect", "to": dest}, | ||||
|         ) | ||||
|         self.assertEqual(response.status_code, 302) | ||||
|         self.assertEqual(response.url, reverse("authentik_core:shell")) | ||||
|  | ||||
|     def test_multi_stage_flow(self): | ||||
|         """Test a full flow with multiple stages""" | ||||
| @ -161,6 +165,10 @@ class TestFlowExecutor(TestCase): | ||||
|         plan: FlowPlan = session[SESSION_KEY_PLAN] | ||||
|         self.assertEqual(len(plan.stages), 1) | ||||
|  | ||||
|     @patch( | ||||
|         "authentik.flows.views.to_stage_response", | ||||
|         TO_STAGE_RESPONSE_MOCK, | ||||
|     ) | ||||
|     def test_reevaluate_remove_last(self): | ||||
|         """Test planner with re-evaluate (last stage is removed)""" | ||||
|         flow = Flow.objects.create( | ||||
|  | ||||
| @ -21,7 +21,12 @@ from authentik.audit.models import cleanse_dict | ||||
| from authentik.core.models import USER_ATTRIBUTE_DEBUG | ||||
| from authentik.flows.exceptions import EmptyFlowException, FlowNonApplicableException | ||||
| from authentik.flows.models import ConfigurableStage, Flow, FlowDesignation, Stage | ||||
| from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER, FlowPlan, FlowPlanner | ||||
| from authentik.flows.planner import ( | ||||
|     PLAN_CONTEXT_PENDING_USER, | ||||
|     PLAN_CONTEXT_REDIRECT, | ||||
|     FlowPlan, | ||||
|     FlowPlanner, | ||||
| ) | ||||
| from authentik.lib.utils.reflection import class_to_path | ||||
| from authentik.lib.utils.urls import is_url_absolute, redirect_with_qs | ||||
| from authentik.policies.http import AccessDeniedResponse | ||||
| @ -83,7 +88,9 @@ class FlowExecutorView(View): | ||||
|                 return to_stage_response(self.request, self.handle_invalid_flow(exc)) | ||||
|             except EmptyFlowException as exc: | ||||
|                 LOGGER.warning("f(exec): Flow is empty", exc=exc) | ||||
|                 return to_stage_response(self.request, self.handle_invalid_flow(exc)) | ||||
|                 # To match behaviour with loading an empty flow plan from cache, | ||||
|                 # we don't show an error message here, but rather call _flow_done() | ||||
|                 return self._flow_done() | ||||
|         # We don't save the Plan after getting the next stage | ||||
|         # as it hasn't been successfully passed yet | ||||
|         next_stage = self.plan.next(self.request) | ||||
| @ -143,11 +150,15 @@ class FlowExecutorView(View): | ||||
|         """User Successfully passed all stages""" | ||||
|         # Since this is wrapped by the ExecutorShell, the next argument is saved in the session | ||||
|         # extract the next param before cancel as that cleans it | ||||
|         next_param = self.request.session.get(SESSION_KEY_GET, {}).get( | ||||
|             NEXT_ARG_NAME, "authentik_core:shell" | ||||
|         ) | ||||
|         next_param = None | ||||
|         if self.plan: | ||||
|             next_param = self.plan.context.get(PLAN_CONTEXT_REDIRECT) | ||||
|         if not next_param: | ||||
|             next_param = self.request.session.get(SESSION_KEY_GET, {}).get( | ||||
|                 NEXT_ARG_NAME, "authentik_core:shell" | ||||
|             ) | ||||
|         self.cancel() | ||||
|         return redirect_with_qs(next_param) | ||||
|         return to_stage_response(self.request, redirect_with_qs(next_param)) | ||||
|  | ||||
|     def stage_ok(self) -> HttpResponse: | ||||
|         """Callback called by stages upon successful completion. | ||||
|  | ||||
| @ -46,7 +46,7 @@ class SecretReconciler(KubernetesObjectReconciler[V1Secret]): | ||||
|                 "authentik_host_insecure": b64string( | ||||
|                     str(self.controller.outpost.config.authentik_host_insecure) | ||||
|                 ), | ||||
|                 "token": b64string(self.controller.outpost.token.token_uuid.hex), | ||||
|                 "token": b64string(self.controller.outpost.token.key), | ||||
|             }, | ||||
|         ) | ||||
|  | ||||
|  | ||||
| @ -113,17 +113,24 @@ class OutpostServiceConnection(models.Model): | ||||
|  | ||||
|     objects = InheritanceManager() | ||||
|  | ||||
|     @property | ||||
|     def state_key(self) -> str: | ||||
|         """Key used to save connection state in cache""" | ||||
|         return f"outpost_service_connection_{self.pk.hex}" | ||||
|  | ||||
|     @property | ||||
|     def state(self) -> OutpostServiceConnectionState: | ||||
|         """Get state of service connection""" | ||||
|         state_key = f"outpost_service_connection_{self.pk.hex}" | ||||
|         state = cache.get(state_key, None) | ||||
|         from authentik.outposts.tasks import outpost_service_connection_state | ||||
|  | ||||
|         state = cache.get(self.state_key, None) | ||||
|         if not state: | ||||
|             state = self._get_state() | ||||
|             cache.set(state_key, state, timeout=0) | ||||
|             outpost_service_connection_state.delay(self.pk) | ||||
|             return OutpostServiceConnectionState("", False) | ||||
|         return state | ||||
|  | ||||
|     def _get_state(self) -> OutpostServiceConnectionState: | ||||
|     def fetch_state(self) -> OutpostServiceConnectionState: | ||||
|         """Fetch current Service Connection state""" | ||||
|         raise NotImplementedError | ||||
|  | ||||
|     @property | ||||
| @ -203,7 +210,7 @@ class DockerServiceConnection(OutpostServiceConnection): | ||||
|             raise ServiceConnectionInvalid from exc | ||||
|         return client | ||||
|  | ||||
|     def _get_state(self) -> OutpostServiceConnectionState: | ||||
|     def fetch_state(self) -> OutpostServiceConnectionState: | ||||
|         try: | ||||
|             client = self.client() | ||||
|             return OutpostServiceConnectionState( | ||||
| @ -239,7 +246,7 @@ class KubernetesServiceConnection(OutpostServiceConnection): | ||||
|     def __str__(self) -> str: | ||||
|         return f"Kubernetes Service-Connection {self.name}" | ||||
|  | ||||
|     def _get_state(self) -> OutpostServiceConnectionState: | ||||
|     def fetch_state(self) -> OutpostServiceConnectionState: | ||||
|         try: | ||||
|             client = self.client() | ||||
|             api_instance = VersionApi(client) | ||||
| @ -247,7 +254,7 @@ class KubernetesServiceConnection(OutpostServiceConnection): | ||||
|             return OutpostServiceConnectionState( | ||||
|                 version=version.git_version, healthy=True | ||||
|             ) | ||||
|         except (OpenApiException, HTTPError): | ||||
|         except (OpenApiException, HTTPError, ServiceConnectionInvalid): | ||||
|             return OutpostServiceConnectionState(version="", healthy=False) | ||||
|  | ||||
|     def client(self) -> ApiClient: | ||||
|  | ||||
| @ -35,21 +35,22 @@ def outpost_controller_all(): | ||||
|  | ||||
|  | ||||
| @CELERY_APP.task() | ||||
| def outpost_service_connection_state(state_pk: Any): | ||||
| def outpost_service_connection_state(connection_pk: Any): | ||||
|     """Update cached state of a service connection""" | ||||
|     connection: OutpostServiceConnection = ( | ||||
|         OutpostServiceConnection.objects.filter(pk=state_pk).select_subclasses().first() | ||||
|         OutpostServiceConnection.objects.filter(pk=connection_pk) | ||||
|         .select_subclasses() | ||||
|         .first() | ||||
|     ) | ||||
|     cache.delete(f"outpost_service_connection_{connection.pk.hex}") | ||||
|     _ = connection.state | ||||
|     state = connection.fetch_state() | ||||
|     cache.set(connection.state_key, state, timeout=None) | ||||
|  | ||||
|  | ||||
| @CELERY_APP.task(bind=True, base=MonitoredTask) | ||||
| def outpost_service_connection_monitor(self: MonitoredTask): | ||||
|     """Regularly check the state of Outpost Service Connections""" | ||||
|     for connection in OutpostServiceConnection.objects.select_subclasses(): | ||||
|         cache.delete(f"outpost_service_connection_{connection.pk.hex}") | ||||
|         _ = connection.state | ||||
|     for connection in OutpostServiceConnection.objects.all(): | ||||
|         outpost_service_connection_state.delay(connection.pk) | ||||
|     self.set_status(TaskResult(TaskResultStatus.SUCCESSFUL)) | ||||
|  | ||||
|  | ||||
|  | ||||
| @ -1,11 +1,16 @@ | ||||
| """policy API Views""" | ||||
| from django.core.cache import cache | ||||
| from django.core.exceptions import ObjectDoesNotExist | ||||
| from rest_framework.mixins import ListModelMixin | ||||
| from rest_framework.request import Request | ||||
| from rest_framework.response import Response | ||||
| from rest_framework.serializers import ( | ||||
|     ModelSerializer, | ||||
|     PrimaryKeyRelatedField, | ||||
|     Serializer, | ||||
|     SerializerMethodField, | ||||
| ) | ||||
| from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet | ||||
| from rest_framework.viewsets import GenericViewSet, ModelViewSet, ReadOnlyModelViewSet | ||||
|  | ||||
| from authentik.policies.forms import GENERAL_FIELDS | ||||
| from authentik.policies.models import Policy, PolicyBinding, PolicyBindingModel | ||||
| @ -68,6 +73,10 @@ class PolicyViewSet(ReadOnlyModelViewSet): | ||||
|  | ||||
|     queryset = Policy.objects.all() | ||||
|     serializer_class = PolicySerializer | ||||
|     filterset_fields = { | ||||
|         "bindings": ["isnull"], | ||||
|         "promptstage": ["isnull"], | ||||
|     } | ||||
|  | ||||
|     def get_queryset(self): | ||||
|         return Policy.objects.select_subclasses() | ||||
| @ -98,3 +107,14 @@ class PolicyBindingViewSet(ModelViewSet): | ||||
|     serializer_class = PolicyBindingSerializer | ||||
|     filterset_fields = ["policy", "target", "enabled", "order", "timeout"] | ||||
|     search_fields = ["policy__name"] | ||||
|  | ||||
|  | ||||
| class PolicyCacheViewSet(ListModelMixin, GenericViewSet): | ||||
|     """Info about cached policies""" | ||||
|  | ||||
|     queryset = Policy.objects.none() | ||||
|     serializer_class = Serializer | ||||
|  | ||||
|     def list(self, request: Request) -> Response: | ||||
|         """Info about cached policies""" | ||||
|         return Response(data={"pagination": {"count": len(cache.keys("policy_*"))}}) | ||||
|  | ||||
| @ -7,7 +7,7 @@ | ||||
|     <label for="" class="pf-c-form__label"></label> | ||||
|     <div class="c-form__horizontal-group"> | ||||
|         <p> | ||||
|             Expression using Python. See <a target="_blank" href="https://goauthentik.io/policies/expression/">here</a> for a list of all variables. | ||||
|             Expression using Python. See <a target="_blank" href="https://goauthentik.io/docs/policies/expression/">here</a> for a list of all variables. | ||||
|         </p> | ||||
|     </div> | ||||
| </div> | ||||
|  | ||||
| @ -18,6 +18,7 @@ from django.utils import dateformat, timezone | ||||
| from django.utils.translation import gettext_lazy as _ | ||||
| from jwkest.jwk import Key, RSAKey, SYMKey, import_rsa_key | ||||
| from jwkest.jws import JWS | ||||
| from rest_framework.serializers import Serializer | ||||
|  | ||||
| from authentik.core.models import ExpiringModel, PropertyMapping, Provider, User | ||||
| from authentik.crypto.models import CertificateKeyPair | ||||
| @ -263,6 +264,12 @@ class OAuth2Provider(Provider): | ||||
|         launch_url = urlparse(main_url) | ||||
|         return main_url.replace(launch_url.path, "") | ||||
|  | ||||
|     @property | ||||
|     def serializer(self) -> Type[Serializer]: | ||||
|         from authentik.providers.oauth2.api import OAuth2ProviderSerializer | ||||
|  | ||||
|         return OAuth2ProviderSerializer | ||||
|  | ||||
|     @property | ||||
|     def form(self) -> Type[ModelForm]: | ||||
|         from authentik.providers.oauth2.forms import OAuth2ProviderForm | ||||
|  | ||||
| @ -4,6 +4,16 @@ | ||||
| {% load i18n %} | ||||
| {% load authentik_utils %} | ||||
|  | ||||
| {% block head %} | ||||
| {{ block.super }} | ||||
| <style> | ||||
| .pf-c-background-image::before { | ||||
|     background-image: url("{% static 'dist/assets/images/flow_background.jpg' %}"); | ||||
|     background-position: center; | ||||
| } | ||||
| </style> | ||||
| {% endblock %} | ||||
|  | ||||
| {% block title %} | ||||
| {% trans 'End session' %} | ||||
| {% endblock %} | ||||
|  | ||||
| @ -7,7 +7,7 @@ | ||||
|     <label for="" class="pf-c-form__label"></label> | ||||
|     <div class="c-form__horizontal-group"> | ||||
|         <p> | ||||
|             Expression using Python. See <a href="https://goauthentik.io/property-mappings/expression/">here</a> for a list of all variables. | ||||
|             Expression using Python. See <a href="https://goauthentik.io/docs/property-mappings/expression/">here</a> for a list of all variables. | ||||
|         </p> | ||||
|     </div> | ||||
| </div> | ||||
|  | ||||
| @ -1,34 +1,6 @@ | ||||
| # Generated by Django 3.1.1 on 2020-09-30 08:10 | ||||
|  | ||||
| from django.apps.registry import Apps | ||||
| from django.db import migrations, models | ||||
| from django.db.backends.base.schema import BaseDatabaseSchemaEditor | ||||
|  | ||||
| SCOPE_AK_PROXY_EXPRESSION = """return { | ||||
|     "ak_proxy": { | ||||
|         "user_attributes": user.group_attributes() | ||||
|     } | ||||
| }""" | ||||
|  | ||||
|  | ||||
| def create_proxy_scope(apps: Apps, schema_editor: BaseDatabaseSchemaEditor): | ||||
|     from authentik.providers.proxy.models import SCOPE_AK_PROXY, ProxyProvider | ||||
|  | ||||
|     ScopeMapping = apps.get_model("authentik_providers_oauth2", "ScopeMapping") | ||||
|  | ||||
|     ScopeMapping.objects.update_or_create( | ||||
|         scope_name=SCOPE_AK_PROXY, | ||||
|         defaults={ | ||||
|             "name": "Autogenerated OAuth2 Mapping: authentik Proxy", | ||||
|             "scope_name": SCOPE_AK_PROXY, | ||||
|             "description": "", | ||||
|             "expression": SCOPE_AK_PROXY_EXPRESSION, | ||||
|         }, | ||||
|     ) | ||||
|  | ||||
|     for provider in ProxyProvider.objects.all(): | ||||
|         provider.set_oauth_defaults() | ||||
|         provider.save() | ||||
|  | ||||
|  | ||||
| class Migration(migrations.Migration): | ||||
| @ -74,5 +46,4 @@ class Migration(migrations.Migration): | ||||
|                 verbose_name="HTTP-Basic Username", | ||||
|             ), | ||||
|         ), | ||||
|         migrations.RunPython(create_proxy_scope), | ||||
|     ] | ||||
|  | ||||
| @ -0,0 +1,41 @@ | ||||
| # Generated by Django 3.1.4 on 2020-12-14 09:42 | ||||
| from django.apps.registry import Apps | ||||
| from django.db import migrations | ||||
| from django.db.backends.base.schema import BaseDatabaseSchemaEditor | ||||
|  | ||||
| SCOPE_AK_PROXY_EXPRESSION = """return { | ||||
|     "ak_proxy": { | ||||
|         "user_attributes": user.group_attributes() | ||||
|     } | ||||
| }""" | ||||
|  | ||||
|  | ||||
| def create_proxy_scope(apps: Apps, schema_editor: BaseDatabaseSchemaEditor): | ||||
|     from authentik.providers.proxy.models import SCOPE_AK_PROXY, ProxyProvider | ||||
|  | ||||
|     ScopeMapping = apps.get_model("authentik_providers_oauth2", "ScopeMapping") | ||||
|  | ||||
|     ScopeMapping.objects.filter(scope_name="pb_proxy").delete() | ||||
|  | ||||
|     ScopeMapping.objects.update_or_create( | ||||
|         scope_name=SCOPE_AK_PROXY, | ||||
|         defaults={ | ||||
|             "name": "Autogenerated OAuth2 Mapping: authentik Proxy", | ||||
|             "scope_name": SCOPE_AK_PROXY, | ||||
|             "description": "", | ||||
|             "expression": SCOPE_AK_PROXY_EXPRESSION, | ||||
|         }, | ||||
|     ) | ||||
|  | ||||
|     for provider in ProxyProvider.objects.all(): | ||||
|         provider.set_oauth_defaults() | ||||
|         provider.save() | ||||
|  | ||||
|  | ||||
| class Migration(migrations.Migration): | ||||
|  | ||||
|     dependencies = [ | ||||
|         ("authentik_providers_proxy", "0009_auto_20201007_1721"), | ||||
|     ] | ||||
|  | ||||
|     operations = [migrations.RunPython(create_proxy_scope)] | ||||
| @ -8,6 +8,7 @@ from django.db import models | ||||
| from django.forms import ModelForm | ||||
| from django.http import HttpRequest | ||||
| from django.utils.translation import gettext as _ | ||||
| from rest_framework.serializers import Serializer | ||||
|  | ||||
| from authentik.crypto.models import CertificateKeyPair | ||||
| from authentik.lib.models import DomainlessURLValidator | ||||
| @ -108,6 +109,12 @@ class ProxyProvider(OutpostModel, OAuth2Provider): | ||||
|  | ||||
|         return ProxyProviderForm | ||||
|  | ||||
|     @property | ||||
|     def serializer(self) -> Type[Serializer]: | ||||
|         from authentik.providers.proxy.api import ProxyProviderSerializer | ||||
|  | ||||
|         return ProxyProviderSerializer | ||||
|  | ||||
|     @property | ||||
|     def launch_url(self) -> Optional[str]: | ||||
|         """Use external_host as launch URL""" | ||||
|  | ||||
| @ -7,6 +7,7 @@ from django.forms import ModelForm | ||||
| from django.http import HttpRequest | ||||
| from django.shortcuts import reverse | ||||
| from django.utils.translation import gettext_lazy as _ | ||||
| from rest_framework.serializers import Serializer | ||||
| from structlog import get_logger | ||||
|  | ||||
| from authentik.core.models import PropertyMapping, Provider | ||||
| @ -145,6 +146,12 @@ class SAMLProvider(Provider): | ||||
|         launch_url = urlparse(self.acs_url) | ||||
|         return self.acs_url.replace(launch_url.path, "") | ||||
|  | ||||
|     @property | ||||
|     def serializer(self) -> Type[Serializer]: | ||||
|         from authentik.providers.saml.api import SAMLPropertyMappingSerializer | ||||
|  | ||||
|         return SAMLPropertyMappingSerializer | ||||
|  | ||||
|     @property | ||||
|     def form(self) -> Type[ModelForm]: | ||||
|         from authentik.providers.saml.forms import SAMLProviderForm | ||||
|  | ||||
| @ -7,7 +7,7 @@ | ||||
|     <label for="" class="pf-c-form__label"></label> | ||||
|     <div class="c-form__horizontal-group"> | ||||
|         <p> | ||||
|             Expression using Python. See <a href="https://goauthentik.io/property-mappings/expression/">here</a> for a list of all variables. | ||||
|             Expression using Python. See <a href="https://goauthentik.io/docs/property-mappings/expression/">here</a> for a list of all variables. | ||||
|         </p> | ||||
|     </div> | ||||
| </div> | ||||
|  | ||||
| @ -105,16 +105,7 @@ class ASGILogger: | ||||
|             # https://code.djangoproject.com/ticket/31508 | ||||
|             # https://github.com/encode/uvicorn/issues/266 | ||||
|             return | ||||
|         try: | ||||
|             await self.app(scope, receive, send_hooked) | ||||
|         except TypeError as exc: | ||||
|             # https://github.com/encode/uvicorn/issues/244 | ||||
|             if exc.args == ( | ||||
|                 "An asyncio.Future, a coroutine or an awaitable is required", | ||||
|             ): | ||||
|                 pass | ||||
|             else: | ||||
|                 raise exc | ||||
|         await self.app(scope, receive, send_hooked) | ||||
|  | ||||
|     def _get_ip(self) -> str: | ||||
|         client_ip = None | ||||
|  | ||||
| @ -7,13 +7,16 @@ class MessageConsumer(JsonWebsocketConsumer): | ||||
|     """Consumer which sends django.contrib.messages Messages over WS. | ||||
|     channel_name is saved into cache with user_id, and when a add_message is called""" | ||||
|  | ||||
|     session_key: str | ||||
|  | ||||
|     def connect(self): | ||||
|         self.accept() | ||||
|         cache.set(f"user_{self.scope['user'].pk}_messages_{self.channel_name}", True) | ||||
|         self.session_key = self.scope["session"].session_key | ||||
|         cache.set(f"user_{self.session_key}_messages_{self.channel_name}", True, None) | ||||
|  | ||||
|     # pylint: disable=unused-argument | ||||
|     def disconnect(self, close_code): | ||||
|         cache.delete(f"user_{self.scope['user'].pk}_messages_{self.channel_name}") | ||||
|         cache.delete(f"user_{self.session_key}_messages_{self.channel_name}") | ||||
|  | ||||
|     def event_update(self, event: dict): | ||||
|         """Event handler which is called by Messages Storage backend""" | ||||
|  | ||||
| @ -16,7 +16,7 @@ class ChannelsStorage(FallbackStorage): | ||||
|         self.channel = get_channel_layer() | ||||
|  | ||||
|     def _store(self, messages: list[Message], response, *args, **kwargs): | ||||
|         prefix = f"user_{self.request.user.pk}_messages_" | ||||
|         prefix = f"user_{self.request.session.session_key}_messages_" | ||||
|         keys = cache.keys(f"{prefix}*") | ||||
|         if len(keys) < 1: | ||||
|             return super()._store(messages, response, *args, **kwargs) | ||||
|  | ||||
| @ -7,7 +7,7 @@ | ||||
|     <label for="" class="pf-c-form__label"></label> | ||||
|     <div class="c-form__horizontal-group"> | ||||
|         <p> | ||||
|             Expression using Python. See <a href="https://goauthentik.io/property-mappings/expression/">here</a> for a list of all variables. | ||||
|             Expression using Python. See <a href="https://goauthentik.io/docs/property-mappings/expression/">here</a> for a list of all variables. | ||||
|         </p> | ||||
|     </div> | ||||
| </div> | ||||
|  | ||||
| @ -15,10 +15,11 @@ from authentik.core.models import User | ||||
| from authentik.flows.models import Flow, in_memory_stage | ||||
| from authentik.flows.planner import ( | ||||
|     PLAN_CONTEXT_PENDING_USER, | ||||
|     PLAN_CONTEXT_REDIRECT, | ||||
|     PLAN_CONTEXT_SSO, | ||||
|     FlowPlanner, | ||||
| ) | ||||
| from authentik.flows.views import SESSION_KEY_PLAN | ||||
| from authentik.flows.views import NEXT_ARG_NAME, SESSION_KEY_GET, SESSION_KEY_PLAN | ||||
| from authentik.lib.utils.urls import redirect_with_qs | ||||
| from authentik.policies.utils import delete_none_keys | ||||
| from authentik.sources.oauth.auth import AuthorizedServiceBackend | ||||
| @ -135,11 +136,17 @@ class OAuthCallback(OAuthClientMixin, View): | ||||
|  | ||||
|     def handle_login_flow(self, flow: Flow, **kwargs) -> HttpResponse: | ||||
|         """Prepare Authentication Plan, redirect user FlowExecutor""" | ||||
|         # Ensure redirect is carried through when user was trying to | ||||
|         # authorize application | ||||
|         final_redirect = self.request.session.get(SESSION_KEY_GET, {}).get( | ||||
|             NEXT_ARG_NAME, "authentik_core:shell" | ||||
|         ) | ||||
|         kwargs.update( | ||||
|             { | ||||
|                 # Since we authenticate the user by their token, they have no backend set | ||||
|                 PLAN_CONTEXT_AUTHENTICATION_BACKEND: "django.contrib.auth.backends.ModelBackend", | ||||
|                 PLAN_CONTEXT_SSO: True, | ||||
|                 PLAN_CONTEXT_REDIRECT: final_redirect, | ||||
|             } | ||||
|         ) | ||||
|         # We run the Flow planner here so we can pass the Pending user in the context | ||||
|  | ||||
| @ -13,10 +13,11 @@ from authentik.core.models import User | ||||
| from authentik.flows.models import Flow | ||||
| from authentik.flows.planner import ( | ||||
|     PLAN_CONTEXT_PENDING_USER, | ||||
|     PLAN_CONTEXT_REDIRECT, | ||||
|     PLAN_CONTEXT_SSO, | ||||
|     FlowPlanner, | ||||
| ) | ||||
| from authentik.flows.views import SESSION_KEY_PLAN | ||||
| from authentik.flows.views import NEXT_ARG_NAME, SESSION_KEY_GET, SESSION_KEY_PLAN | ||||
| from authentik.lib.utils.urls import redirect_with_qs | ||||
| from authentik.policies.utils import delete_none_keys | ||||
| from authentik.sources.saml.exceptions import ( | ||||
| @ -54,11 +55,14 @@ class ResponseProcessor: | ||||
|     _root: Any | ||||
|     _root_xml: str | ||||
|  | ||||
|     _http_request: HttpRequest | ||||
|  | ||||
|     def __init__(self, source: SAMLSource): | ||||
|         self._source = source | ||||
|  | ||||
|     def parse(self, request: HttpRequest): | ||||
|         """Check if `request` contains SAML Response data, parse and validate it.""" | ||||
|         self._http_request = request | ||||
|         # First off, check if we have any SAML Data at all. | ||||
|         raw_response = request.POST.get("SAMLResponse", None) | ||||
|         if not raw_response: | ||||
| @ -187,6 +191,11 @@ class ResponseProcessor: | ||||
|  | ||||
|         name_id_filter = self._get_name_id_filter() | ||||
|         matching_users = User.objects.filter(**name_id_filter) | ||||
|         # Ensure redirect is carried through when user was trying to | ||||
|         # authorize application | ||||
|         final_redirect = self._http_request.session.get(SESSION_KEY_GET, {}).get( | ||||
|             NEXT_ARG_NAME, "authentik_core:shell" | ||||
|         ) | ||||
|         if matching_users.exists(): | ||||
|             # User exists already, switch to authentication flow | ||||
|             return self._flow_response( | ||||
| @ -195,6 +204,7 @@ class ResponseProcessor: | ||||
|                 **{ | ||||
|                     PLAN_CONTEXT_PENDING_USER: matching_users.first(), | ||||
|                     PLAN_CONTEXT_AUTHENTICATION_BACKEND: DEFAULT_BACKEND, | ||||
|                     PLAN_CONTEXT_REDIRECT: final_redirect, | ||||
|                 }, | ||||
|             ) | ||||
|         return self._flow_response( | ||||
|  | ||||
| @ -10,8 +10,8 @@ services: | ||||
|       - internal | ||||
|     environment: | ||||
|       - POSTGRES_PASSWORD=${PG_PASS:-thisisnotagoodpassword} | ||||
|       - POSTGRES_USER=authentik | ||||
|       - POSTGRES_DB=authentik | ||||
|       - POSTGRES_USER=${PG_USER:-authentik} | ||||
|       - POSTGRES_DB=${PG_DB:-authentik} | ||||
|     env_file: | ||||
|       - .env | ||||
|   redis: | ||||
| @ -19,11 +19,13 @@ services: | ||||
|     networks: | ||||
|       - internal | ||||
|   server: | ||||
|     image: beryju/authentik:${AUTHENTIK_TAG:-0.13.0-rc4} | ||||
|     image: beryju/authentik:${AUTHENTIK_TAG:-0.13.3-stable} | ||||
|     command: server | ||||
|     environment: | ||||
|       AUTHENTIK_REDIS__HOST: redis | ||||
|       AUTHENTIK_POSTGRESQL__HOST: postgresql | ||||
|       AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik} | ||||
|       AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik} | ||||
|       AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS} | ||||
|     volumes: | ||||
|       - ./media:/media | ||||
| @ -42,13 +44,15 @@ services: | ||||
|     env_file: | ||||
|       - .env | ||||
|   worker: | ||||
|     image: beryju/authentik:${AUTHENTIK_TAG:-0.13.0-rc4} | ||||
|     image: beryju/authentik:${AUTHENTIK_TAG:-0.13.3-stable} | ||||
|     command: worker | ||||
|     networks: | ||||
|       - internal | ||||
|     environment: | ||||
|       AUTHENTIK_REDIS__HOST: redis | ||||
|       AUTHENTIK_POSTGRESQL__HOST: postgresql | ||||
|       AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik} | ||||
|       AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik} | ||||
|       AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS} | ||||
|     volumes: | ||||
|       - ./backups:/backups | ||||
| @ -56,7 +60,7 @@ services: | ||||
|     env_file: | ||||
|       - .env | ||||
|   static: | ||||
|     image: beryju/authentik-static:${AUTHENTIK_TAG:-0.13.0-rc4} | ||||
|     image: beryju/authentik-static:${AUTHENTIK_TAG:-0.13.3-stable} | ||||
|     networks: | ||||
|       - internal | ||||
|     labels: | ||||
| @ -68,7 +72,7 @@ services: | ||||
|       traefik.http.services.static-service.loadbalancer.healthcheck.path: / | ||||
|       traefik.http.services.static-service.loadbalancer.server.port: '80' | ||||
|     volumes: | ||||
|       - ./media:/media | ||||
|       - ./media:/usr/share/nginx/html/media | ||||
|   traefik: | ||||
|     image: traefik:2.3 | ||||
|     command: | ||||
| @ -81,7 +85,6 @@ services: | ||||
|     volumes: | ||||
|       - /var/run/docker.sock:/var/run/docker.sock:ro | ||||
|     ports: | ||||
|       - "0.0.0.0:80:80" | ||||
|       - "0.0.0.0:443:443" | ||||
|       - "127.0.0.1:8080:8080" | ||||
|     networks: | ||||
|  | ||||
| @ -4,7 +4,7 @@ name: authentik | ||||
| home: https://goauthentik.io | ||||
| sources: | ||||
|   - https://github.com/BeryJu/authentik | ||||
| version: "0.13.0-rc4" | ||||
| version: "0.13.3-stable" | ||||
| icon: https://raw.githubusercontent.com/BeryJu/authentik/master/web/icons/icon.svg | ||||
| dependencies: | ||||
|   - name: postgresql | ||||
|  | ||||
| @ -4,7 +4,7 @@ | ||||
| |-----------------------------------|-------------------------|-------------| | ||||
| | image.name                        | beryju/authentik         | Image used to run the authentik server and worker | | ||||
| | image.name_static                 | beryju/authentik-static  | Image used to run the authentik static server (CSS and JS Files) | | ||||
| | image.tag                         | 0.13.0-rc4              | Image tag | | ||||
| | image.tag                         | 0.13.3-stable              | Image tag | | ||||
| | image.pullPolicy                  | IfNotPresent            | Image Pull Policy used for all deployments | | ||||
| | serverReplicas                    | 1                       | Replicas for the Server deployment | | ||||
| | workerReplicas                    | 1                       | Replicas for the Worker deployment | | ||||
|  | ||||
| @ -36,6 +36,10 @@ spec: | ||||
|             backend: | ||||
|               serviceName: {{ $fullName }}-static | ||||
|               servicePort: http | ||||
|           - path: /media/ | ||||
|             backend: | ||||
|               serviceName: {{ $fullName }}-static | ||||
|               servicePort: http | ||||
|           - path: /robots.txt | ||||
|             backend: | ||||
|               serviceName: {{ $fullName }}-static | ||||
|  | ||||
| @ -5,7 +5,7 @@ image: | ||||
|   name: beryju/authentik | ||||
|   name_static: beryju/authentik-static | ||||
|   name_outposts: beryju/authentik # Prefix used for Outpost deployments, Outpost type and version is appended | ||||
|   tag: 0.13.0-rc4 | ||||
|   tag: 0.13.3-stable | ||||
|   pullPolicy: IfNotPresent | ||||
|  | ||||
| serverReplicas: 1 | ||||
|  | ||||
							
								
								
									
										10
									
								
								proxy/go.mod
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								proxy/go.mod
									
									
									
									
									
								
							| @ -5,12 +5,12 @@ go 1.14 | ||||
| require ( | ||||
| 	cloud.google.com/go v0.64.0 // indirect | ||||
| 	github.com/coreos/go-oidc v2.2.1+incompatible | ||||
| 	github.com/getsentry/sentry-go v0.7.0 | ||||
| 	github.com/go-openapi/errors v0.19.9 | ||||
| 	github.com/getsentry/sentry-go v0.9.0 | ||||
| 	github.com/go-openapi/errors v0.19.9 // indirect | ||||
| 	github.com/go-openapi/runtime v0.19.24 | ||||
| 	github.com/go-openapi/strfmt v0.19.11 | ||||
| 	github.com/go-openapi/swag v0.19.12 | ||||
| 	github.com/go-openapi/validate v0.19.15 | ||||
| 	github.com/go-openapi/swag v0.19.12 // indirect | ||||
| 	github.com/go-openapi/validate v0.19.15 // indirect | ||||
| 	github.com/go-redis/redis/v7 v7.4.0 // indirect | ||||
| 	github.com/go-swagger/go-swagger v0.25.0 // indirect | ||||
| 	github.com/gorilla/handlers v1.5.1 // indirect | ||||
| @ -22,7 +22,7 @@ require ( | ||||
| 	github.com/oauth2-proxy/oauth2-proxy v1.1.2-0.20200817154438-5fa5b3186f39 | ||||
| 	github.com/pelletier/go-toml v1.8.1 // indirect | ||||
| 	github.com/pquerna/cachecontrol v0.0.0-20200819021114-67c6ae64274f // indirect | ||||
| 	github.com/recws-org/recws v1.2.1 | ||||
| 	github.com/recws-org/recws v1.2.2 | ||||
| 	github.com/sirupsen/logrus v1.7.0 | ||||
| 	github.com/spf13/afero v1.4.1 // indirect | ||||
| 	github.com/spf13/cast v1.3.1 // indirect | ||||
|  | ||||
							
								
								
									
										24
									
								
								proxy/go.sum
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								proxy/go.sum
									
									
									
									
									
								
							| @ -35,13 +35,17 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX | ||||
| cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= | ||||
| dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= | ||||
| github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= | ||||
| github.com/BeryJu/authentik v0.0.0-20201213234502-f0f32453882b h1:tLc7ERt2fWSu14nXdsER4EP62KUPXwAB0OeLVAA4Rx0= | ||||
| github.com/BeryJu/authentik v0.0.0-20201214075318-41f9097592da h1:XB/MCgb0K+ngEETjBYKGiXcN2des8YtANetYboeT4Lg= | ||||
| github.com/Bose/minisentinel v0.0.0-20200130220412-917c5a9223bb h1:ZVN4Iat3runWOFLaBCDVU5a9X/XikSRBosye++6gojw= | ||||
| github.com/Bose/minisentinel v0.0.0-20200130220412-917c5a9223bb/go.mod h1:WsAABbY4HQBgd3mGuG4KMNTbHJCPvx9IVBHzysbknss= | ||||
| github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= | ||||
| github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= | ||||
| github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= | ||||
| github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw= | ||||
| github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= | ||||
| github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w= | ||||
| github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo= | ||||
| github.com/FZambia/sentinel v1.0.0 h1:KJ0ryjKTZk5WMp0dXvSdNqp3lFaW1fNFuEYfrkLOYIc= | ||||
| github.com/FZambia/sentinel v1.0.0/go.mod h1:ytL1Am/RLlAoAXG6Kj5LNuw/TRRQrv2rt2FT26vP5gI= | ||||
| github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= | ||||
| @ -139,6 +143,8 @@ github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4 | ||||
| github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= | ||||
| github.com/getsentry/sentry-go v0.7.0 h1:MR2yfR4vFfv/2+iBuSnkdQwVg7N9cJzihZ6KJu7srwQ= | ||||
| github.com/getsentry/sentry-go v0.7.0/go.mod h1:pLFpD2Y5RHIKF9Bw3KH6/68DeN2K/XBJd8awjdPnUwg= | ||||
| github.com/getsentry/sentry-go v0.9.0 h1:KIfpY/D9hX3gWAEd3d8z6ImuHNWtqEsjlpdF8zXFsHM= | ||||
| github.com/getsentry/sentry-go v0.9.0/go.mod h1:kELm/9iCblqUYh+ZRML7PNdCvEuw24wBvJPYyi86cws= | ||||
| github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= | ||||
| github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= | ||||
| github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= | ||||
| @ -409,6 +415,8 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt | ||||
| github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= | ||||
| github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= | ||||
| github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0/go.mod h1:pMCz62A0xJL6I+umB2YTlFRwWXaDFA0jy+5HzGiJjqI= | ||||
| github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk= | ||||
| github.com/iris-contrib/pongo2 v0.0.1/go.mod h1:Ssh+00+3GAZqSQb30AvBRNxBx7rf0GqwkjqxNd0u65g= | ||||
| github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw= | ||||
| github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA= | ||||
| github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= | ||||
| @ -438,9 +446,14 @@ github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q | ||||
| github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= | ||||
| github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= | ||||
| github.com/kataras/golog v0.0.9/go.mod h1:12HJgwBIZFNGL0EJnMRhmvGA0PQGx8VFwrZtM4CqbAk= | ||||
| github.com/kataras/golog v0.0.10/go.mod h1:yJ8YKCmyL+nWjERB90Qwn+bdyBZsaQwU3bTVFgkFIp8= | ||||
| github.com/kataras/iris/v12 v12.0.1/go.mod h1:udK4vLQKkdDqMGJJVd/msuMtN6hpYJhg/lSzuxjhO+U= | ||||
| github.com/kataras/iris/v12 v12.1.8/go.mod h1:LMYy4VlP67TQ3Zgriz8RE2h2kMZV2SgMYbq3UhfoFmE= | ||||
| github.com/kataras/neffos v0.0.10/go.mod h1:ZYmJC07hQPW67eKuzlfY7SO3bC0mw83A3j6im82hfqw= | ||||
| github.com/kataras/neffos v0.0.14/go.mod h1:8lqADm8PnbeFfL7CLXh1WHw53dG27MC3pgi2R1rmoTE= | ||||
| github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d/go.mod h1:NV88laa9UiiDuX9AhMbDPkGYSPugBOV6yTZB1l2K9Z0= | ||||
| github.com/kataras/pio v0.0.2/go.mod h1:hAoW0t9UmXi4R5Oyq5Z4irTbaTsOemSrDGUtaTl7Dro= | ||||
| github.com/kataras/sitemap v0.0.5/go.mod h1:KY2eugMKiPwsJgx7+U103YZehfvNGOXURubcGyk0Bz8= | ||||
| github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= | ||||
| github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= | ||||
| github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= | ||||
| @ -448,6 +461,7 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o | ||||
| github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= | ||||
| github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= | ||||
| github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= | ||||
| github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= | ||||
| github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= | ||||
| github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= | ||||
| github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= | ||||
| @ -496,6 +510,7 @@ github.com/mbland/hmacauth v0.0.0-20170912233209-44256dfd4bfa h1:hI1uC2A3vJFjwvB | ||||
| github.com/mbland/hmacauth v0.0.0-20170912233209-44256dfd4bfa/go.mod h1:8vxFeeg++MqgCHwehSuwTlYCF0ALyDJbYJ1JsKi7v6s= | ||||
| github.com/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed/go.mod h1:dSsfyI2zABAdhcbvkXqgxOxrCsbYeHCPgrZkku60dSg= | ||||
| github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQGvsUt6O3Pj+LDCQ= | ||||
| github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8= | ||||
| github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= | ||||
| github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= | ||||
| github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= | ||||
| @ -519,8 +534,11 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb | ||||
| github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= | ||||
| github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= | ||||
| github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= | ||||
| github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= | ||||
| github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM= | ||||
| github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= | ||||
| github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4= | ||||
| github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= | ||||
| github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= | ||||
| github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= | ||||
| github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= | ||||
| @ -577,6 +595,8 @@ github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7z | ||||
| github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= | ||||
| github.com/recws-org/recws v1.2.1 h1:bYocRkAsS71hlQ9AMCVS+hYXHEgEyQsAbYKXf394gZ8= | ||||
| github.com/recws-org/recws v1.2.1/go.mod h1:SxTgwQU/jqYSzEgUh4ifDxq/7enApS150f8nZ5Sczk8= | ||||
| github.com/recws-org/recws v1.2.2 h1:TkyyCEgMjsr1D2fnutY/DPhGnUKCLpJeXDAGy6rLmGE= | ||||
| github.com/recws-org/recws v1.2.2/go.mod h1:SxTgwQU/jqYSzEgUh4ifDxq/7enApS150f8nZ5Sczk8= | ||||
| github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= | ||||
| github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= | ||||
| github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= | ||||
| @ -584,6 +604,7 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR | ||||
| github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= | ||||
| github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= | ||||
| github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= | ||||
| github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g= | ||||
| github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= | ||||
| github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= | ||||
| github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= | ||||
| @ -711,6 +732,7 @@ golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8U | ||||
| golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | ||||
| golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | ||||
| golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | ||||
| golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= | ||||
| golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= | ||||
| golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= | ||||
| golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de h1:ikNHVSjEfnvz6sxdSPCaPt572qowuyMDMJLLm3Db3ig= | ||||
| @ -1046,6 +1068,7 @@ gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8 | ||||
| gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= | ||||
| gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= | ||||
| gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= | ||||
| gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= | ||||
| gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= | ||||
| gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= | ||||
| gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= | ||||
| @ -1070,6 +1093,7 @@ gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= | ||||
| gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | ||||
| gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= | ||||
| gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= | ||||
| gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||||
| gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= | ||||
| gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||||
| gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||||
|  | ||||
| @ -59,6 +59,7 @@ func getCommonOptions() *options.Options { | ||||
| } | ||||
|  | ||||
| func doGlobalSetup(config map[string]interface{}) { | ||||
| 	log.SetFormatter(&log.JSONFormatter{}) | ||||
| 	switch config[ConfigLogLevel].(string) { | ||||
| 	case "debug": | ||||
| 		log.SetLevel(log.DebugLevel) | ||||
|  | ||||
| @ -1,3 +1,3 @@ | ||||
| package pkg | ||||
|  | ||||
| const VERSION = "0.13.0-rc4" | ||||
| const VERSION = "0.13.3-stable" | ||||
|  | ||||
							
								
								
									
										341
									
								
								swagger.yaml
									
									
									
									
									
								
							
							
						
						
									
										341
									
								
								swagger.yaml
									
									
									
									
									
								
							| @ -22,11 +22,11 @@ paths: | ||||
|   /admin/metrics/: | ||||
|     get: | ||||
|       operationId: admin_metrics_list | ||||
|       description: Return single instance of AdministrationMetricsSerializer | ||||
|       description: Login Metrics per 1h | ||||
|       parameters: [] | ||||
|       responses: | ||||
|         '200': | ||||
|           description: Overview View | ||||
|           description: Login Metrics per 1h | ||||
|           schema: | ||||
|             description: '' | ||||
|             type: array | ||||
| @ -35,22 +35,6 @@ paths: | ||||
|       tags: | ||||
|         - admin | ||||
|     parameters: [] | ||||
|   /admin/overview/: | ||||
|     get: | ||||
|       operationId: admin_overview_list | ||||
|       description: Return single instance of AdministrationOverviewSerializer | ||||
|       parameters: [] | ||||
|       responses: | ||||
|         '200': | ||||
|           description: Overview View | ||||
|           schema: | ||||
|             description: '' | ||||
|             type: array | ||||
|             items: | ||||
|               $ref: '#/definitions/AdministrationOverview' | ||||
|       tags: | ||||
|         - admin | ||||
|     parameters: [] | ||||
|   /admin/system_tasks/: | ||||
|     get: | ||||
|       operationId: admin_system_tasks_list | ||||
| @ -82,6 +66,95 @@ paths: | ||||
|         in: path | ||||
|         required: true | ||||
|         type: string | ||||
|   /admin/version/: | ||||
|     get: | ||||
|       operationId: admin_version_list | ||||
|       description: Get running and latest version. | ||||
|       parameters: | ||||
|         - name: ordering | ||||
|           in: query | ||||
|           description: Which field to use when ordering the results. | ||||
|           required: false | ||||
|           type: string | ||||
|         - name: search | ||||
|           in: query | ||||
|           description: A search term. | ||||
|           required: false | ||||
|           type: string | ||||
|         - name: page | ||||
|           in: query | ||||
|           description: A page number within the paginated result set. | ||||
|           required: false | ||||
|           type: integer | ||||
|         - name: page_size | ||||
|           in: query | ||||
|           description: Number of results to return per page. | ||||
|           required: false | ||||
|           type: integer | ||||
|       responses: | ||||
|         '200': | ||||
|           description: Get running and latest version. | ||||
|           schema: | ||||
|             description: '' | ||||
|             type: array | ||||
|             items: | ||||
|               $ref: '#/definitions/Version' | ||||
|       tags: | ||||
|         - admin | ||||
|     parameters: [] | ||||
|   /admin/workers/: | ||||
|     get: | ||||
|       operationId: admin_workers_list | ||||
|       description: Get currently connected worker count. | ||||
|       parameters: | ||||
|         - name: ordering | ||||
|           in: query | ||||
|           description: Which field to use when ordering the results. | ||||
|           required: false | ||||
|           type: string | ||||
|         - name: search | ||||
|           in: query | ||||
|           description: A search term. | ||||
|           required: false | ||||
|           type: string | ||||
|         - name: page | ||||
|           in: query | ||||
|           description: A page number within the paginated result set. | ||||
|           required: false | ||||
|           type: integer | ||||
|         - name: page_size | ||||
|           in: query | ||||
|           description: Number of results to return per page. | ||||
|           required: false | ||||
|           type: integer | ||||
|       responses: | ||||
|         '200': | ||||
|           description: '' | ||||
|           schema: | ||||
|             required: | ||||
|               - count | ||||
|               - results | ||||
|             type: object | ||||
|             properties: | ||||
|               count: | ||||
|                 type: integer | ||||
|               next: | ||||
|                 type: string | ||||
|                 format: uri | ||||
|                 x-nullable: true | ||||
|               previous: | ||||
|                 type: string | ||||
|                 format: uri | ||||
|                 x-nullable: true | ||||
|               results: | ||||
|                 type: array | ||||
|                 items: | ||||
|                   description: '' | ||||
|                   type: object | ||||
|                   properties: {} | ||||
|       tags: | ||||
|         - admin | ||||
|     parameters: [] | ||||
|   /audit/events/: | ||||
|     get: | ||||
|       operationId: audit_events_list | ||||
| @ -1062,6 +1135,59 @@ paths: | ||||
|         required: true | ||||
|         type: string | ||||
|         format: uuid | ||||
|   /flows/cached/: | ||||
|     get: | ||||
|       operationId: flows_cached_list | ||||
|       description: Info about cached flows | ||||
|       parameters: | ||||
|         - name: ordering | ||||
|           in: query | ||||
|           description: Which field to use when ordering the results. | ||||
|           required: false | ||||
|           type: string | ||||
|         - name: search | ||||
|           in: query | ||||
|           description: A search term. | ||||
|           required: false | ||||
|           type: string | ||||
|         - name: page | ||||
|           in: query | ||||
|           description: A page number within the paginated result set. | ||||
|           required: false | ||||
|           type: integer | ||||
|         - name: page_size | ||||
|           in: query | ||||
|           description: Number of results to return per page. | ||||
|           required: false | ||||
|           type: integer | ||||
|       responses: | ||||
|         '200': | ||||
|           description: '' | ||||
|           schema: | ||||
|             required: | ||||
|               - count | ||||
|               - results | ||||
|             type: object | ||||
|             properties: | ||||
|               count: | ||||
|                 type: integer | ||||
|               next: | ||||
|                 type: string | ||||
|                 format: uri | ||||
|                 x-nullable: true | ||||
|               previous: | ||||
|                 type: string | ||||
|                 format: uri | ||||
|                 x-nullable: true | ||||
|               results: | ||||
|                 type: array | ||||
|                 items: | ||||
|                   description: '' | ||||
|                   type: object | ||||
|                   properties: {} | ||||
|       tags: | ||||
|         - flows | ||||
|     parameters: [] | ||||
|   /flows/instances/: | ||||
|     get: | ||||
|       operationId: flows_instances_list | ||||
| @ -1702,6 +1828,16 @@ paths: | ||||
|       operationId: policies_all_list | ||||
|       description: Policy Viewset | ||||
|       parameters: | ||||
|         - name: bindings__isnull | ||||
|           in: query | ||||
|           description: '' | ||||
|           required: false | ||||
|           type: string | ||||
|         - name: promptstage__isnull | ||||
|           in: query | ||||
|           description: '' | ||||
|           required: false | ||||
|           type: string | ||||
|         - name: ordering | ||||
|           in: query | ||||
|           description: Which field to use when ordering the results. | ||||
| @ -1919,6 +2055,59 @@ paths: | ||||
|         required: true | ||||
|         type: string | ||||
|         format: uuid | ||||
|   /policies/cached/: | ||||
|     get: | ||||
|       operationId: policies_cached_list | ||||
|       description: Info about cached policies | ||||
|       parameters: | ||||
|         - name: ordering | ||||
|           in: query | ||||
|           description: Which field to use when ordering the results. | ||||
|           required: false | ||||
|           type: string | ||||
|         - name: search | ||||
|           in: query | ||||
|           description: A search term. | ||||
|           required: false | ||||
|           type: string | ||||
|         - name: page | ||||
|           in: query | ||||
|           description: A page number within the paginated result set. | ||||
|           required: false | ||||
|           type: integer | ||||
|         - name: page_size | ||||
|           in: query | ||||
|           description: Number of results to return per page. | ||||
|           required: false | ||||
|           type: integer | ||||
|       responses: | ||||
|         '200': | ||||
|           description: '' | ||||
|           schema: | ||||
|             required: | ||||
|               - count | ||||
|               - results | ||||
|             type: object | ||||
|             properties: | ||||
|               count: | ||||
|                 type: integer | ||||
|               next: | ||||
|                 type: string | ||||
|                 format: uri | ||||
|                 x-nullable: true | ||||
|               previous: | ||||
|                 type: string | ||||
|                 format: uri | ||||
|                 x-nullable: true | ||||
|               results: | ||||
|                 type: array | ||||
|                 items: | ||||
|                   description: '' | ||||
|                   type: object | ||||
|                   properties: {} | ||||
|       tags: | ||||
|         - policies | ||||
|     parameters: [] | ||||
|   /policies/dummy/: | ||||
|     get: | ||||
|       operationId: policies_dummy_list | ||||
| @ -3264,6 +3453,11 @@ paths: | ||||
|       operationId: providers_all_list | ||||
|       description: Provider Viewset | ||||
|       parameters: | ||||
|         - name: application__isnull | ||||
|           in: query | ||||
|           description: '' | ||||
|           required: false | ||||
|           type: string | ||||
|         - name: ordering | ||||
|           in: query | ||||
|           description: Which field to use when ordering the results. | ||||
| @ -3309,6 +3503,22 @@ paths: | ||||
|                   $ref: '#/definitions/Provider' | ||||
|       tags: | ||||
|         - providers | ||||
|     post: | ||||
|       operationId: providers_all_create | ||||
|       description: Provider Viewset | ||||
|       parameters: | ||||
|         - name: data | ||||
|           in: body | ||||
|           required: true | ||||
|           schema: | ||||
|             $ref: '#/definitions/Provider' | ||||
|       responses: | ||||
|         '201': | ||||
|           description: '' | ||||
|           schema: | ||||
|             $ref: '#/definitions/Provider' | ||||
|       tags: | ||||
|         - providers | ||||
|     parameters: [] | ||||
|   /providers/all/{id}/: | ||||
|     get: | ||||
| @ -3322,6 +3532,47 @@ paths: | ||||
|             $ref: '#/definitions/Provider' | ||||
|       tags: | ||||
|         - providers | ||||
|     put: | ||||
|       operationId: providers_all_update | ||||
|       description: Provider Viewset | ||||
|       parameters: | ||||
|         - name: data | ||||
|           in: body | ||||
|           required: true | ||||
|           schema: | ||||
|             $ref: '#/definitions/Provider' | ||||
|       responses: | ||||
|         '200': | ||||
|           description: '' | ||||
|           schema: | ||||
|             $ref: '#/definitions/Provider' | ||||
|       tags: | ||||
|         - providers | ||||
|     patch: | ||||
|       operationId: providers_all_partial_update | ||||
|       description: Provider Viewset | ||||
|       parameters: | ||||
|         - name: data | ||||
|           in: body | ||||
|           required: true | ||||
|           schema: | ||||
|             $ref: '#/definitions/Provider' | ||||
|       responses: | ||||
|         '200': | ||||
|           description: '' | ||||
|           schema: | ||||
|             $ref: '#/definitions/Provider' | ||||
|       tags: | ||||
|         - providers | ||||
|     delete: | ||||
|       operationId: providers_all_delete | ||||
|       description: Provider Viewset | ||||
|       parameters: [] | ||||
|       responses: | ||||
|         '204': | ||||
|           description: '' | ||||
|       tags: | ||||
|         - providers | ||||
|     parameters: | ||||
|       - name: id | ||||
|         in: path | ||||
| @ -6421,7 +6672,7 @@ paths: | ||||
|         format: uuid | ||||
| definitions: | ||||
|   AdministrationMetrics: | ||||
|     description: Overview View | ||||
|     description: Login Metrics per 1h | ||||
|     type: object | ||||
|     properties: | ||||
|       logins_per_1h: | ||||
| @ -6432,38 +6683,6 @@ definitions: | ||||
|         title: Logins failed per 1h | ||||
|         type: string | ||||
|         readOnly: true | ||||
|   AdministrationOverview: | ||||
|     description: Overview View | ||||
|     type: object | ||||
|     properties: | ||||
|       version: | ||||
|         title: Version | ||||
|         type: string | ||||
|         readOnly: true | ||||
|       version_latest: | ||||
|         title: Version latest | ||||
|         type: string | ||||
|         readOnly: true | ||||
|       worker_count: | ||||
|         title: Worker count | ||||
|         type: integer | ||||
|         readOnly: true | ||||
|       providers_without_application: | ||||
|         title: Providers without application | ||||
|         type: integer | ||||
|         readOnly: true | ||||
|       policies_without_binding: | ||||
|         title: Policies without binding | ||||
|         type: integer | ||||
|         readOnly: true | ||||
|       cached_policies: | ||||
|         title: Cached policies | ||||
|         type: integer | ||||
|         readOnly: true | ||||
|       cached_flows: | ||||
|         title: Cached flows | ||||
|         type: integer | ||||
|         readOnly: true | ||||
|   Task: | ||||
|     description: Serialize TaskInfo and TaskResult | ||||
|     required: | ||||
| @ -6494,6 +6713,22 @@ definitions: | ||||
|         type: array | ||||
|         items: | ||||
|           type: string | ||||
|   Version: | ||||
|     description: Get running and latest version. | ||||
|     type: object | ||||
|     properties: | ||||
|       version_current: | ||||
|         title: Version current | ||||
|         type: string | ||||
|         readOnly: true | ||||
|       version_latest: | ||||
|         title: Version latest | ||||
|         type: string | ||||
|         readOnly: true | ||||
|       outdated: | ||||
|         title: Outdated | ||||
|         type: boolean | ||||
|         readOnly: true | ||||
|   Event: | ||||
|     description: Event Serializer | ||||
|     required: | ||||
| @ -7480,6 +7715,7 @@ definitions: | ||||
|     description: Provider Serializer | ||||
|     required: | ||||
|       - name | ||||
|       - application | ||||
|       - authorization_flow | ||||
|     type: object | ||||
|     properties: | ||||
| @ -7491,6 +7727,9 @@ definitions: | ||||
|         title: Name | ||||
|         type: string | ||||
|         minLength: 1 | ||||
|       application: | ||||
|         title: Application | ||||
|         type: string | ||||
|       authorization_flow: | ||||
|         title: Authorization flow | ||||
|         description: Flow used when authorizing this provider. | ||||
|  | ||||
							
								
								
									
										298
									
								
								web/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										298
									
								
								web/package-lock.json
									
									
									
										generated
									
									
									
								
							| @ -102,14 +102,14 @@ | ||||
|             } | ||||
|         }, | ||||
|         "@patternfly/patternfly": { | ||||
|             "version": "4.65.6", | ||||
|             "resolved": "https://registry.npmjs.org/@patternfly/patternfly/-/patternfly-4.65.6.tgz", | ||||
|             "integrity": "sha512-dENO2nZbf5SoEH68coW9U+6FpZmdVnFVjztl7rUeWUPSBUuF1eWld5LT03Q6PVoZuWqqbJxFJodyFKwLb+L9vw==" | ||||
|             "version": "4.70.2", | ||||
|             "resolved": "https://registry.npmjs.org/@patternfly/patternfly/-/patternfly-4.70.2.tgz", | ||||
|             "integrity": "sha512-XKCHnOjx1JThY3s98AJhsApSsGHPvEdlY7r+b18OecqUnmThVGw3nslzYYrwfCGlJ/xQtV5so29SduH2/uhHzA==" | ||||
|         }, | ||||
|         "@rollup/plugin-typescript": { | ||||
|             "version": "8.0.0", | ||||
|             "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-8.0.0.tgz", | ||||
|             "integrity": "sha512-2L/kKvM5U4VOm+yVMvPIBF3yMZtQUyopf4YIT+KQbqZBZ8Fsdm7X6yeezy92PMyvvHQG1Pa322MVwxPojQvukA==", | ||||
|             "version": "8.1.0", | ||||
|             "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-8.1.0.tgz", | ||||
|             "integrity": "sha512-pyQlcGQYRsONUDwXK3ckGPHjPzmjlq4sinzr7emW8ZMb2oZjg9WLcdcP8wyHSvBjvHrLzMayyPy079RROqb4vw==", | ||||
|             "dev": true, | ||||
|             "requires": { | ||||
|                 "@rollup/pluginutils": "^3.1.0", | ||||
| @ -142,13 +142,13 @@ | ||||
|             } | ||||
|         }, | ||||
|         "@sentry/browser": { | ||||
|             "version": "5.29.0", | ||||
|             "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-5.29.0.tgz", | ||||
|             "integrity": "sha512-kRlt1mE2wrYjspnIupNnPxqsUrRuy02SuXhbpP7J6uu8QasoEmJ78hk0hHz4jOZRmuWwfs2zIXD4tLGgWOKq8A==", | ||||
|             "version": "5.29.2", | ||||
|             "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-5.29.2.tgz", | ||||
|             "integrity": "sha512-uxZ7y7rp85tJll+RZtXRhXPbnFnOaxZqJEv05vJlXBtBNLQtlczV5iCtU9mZRLVHDtmZ5VVKUV8IKXntEqqDpQ==", | ||||
|             "requires": { | ||||
|                 "@sentry/core": "5.29.0", | ||||
|                 "@sentry/types": "5.29.0", | ||||
|                 "@sentry/utils": "5.29.0", | ||||
|                 "@sentry/core": "5.29.2", | ||||
|                 "@sentry/types": "5.29.2", | ||||
|                 "@sentry/utils": "5.29.2", | ||||
|                 "tslib": "^1.9.3" | ||||
|             }, | ||||
|             "dependencies": { | ||||
| @ -160,14 +160,14 @@ | ||||
|             } | ||||
|         }, | ||||
|         "@sentry/core": { | ||||
|             "version": "5.29.0", | ||||
|             "resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.29.0.tgz", | ||||
|             "integrity": "sha512-a1sZBJ2u3NG0YDlGvOTwUCWiNjhfmDtAQiKK1o6RIIbcrWy9TlSps7CYDkBP239Y3A4pnvohjEEKEP3v3L3LZQ==", | ||||
|             "version": "5.29.2", | ||||
|             "resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.29.2.tgz", | ||||
|             "integrity": "sha512-7WYkoxB5IdlNEbwOwqSU64erUKH4laavPsM0/yQ+jojM76ErxlgEF0u//p5WaLPRzh3iDSt6BH+9TL45oNZeZw==", | ||||
|             "requires": { | ||||
|                 "@sentry/hub": "5.29.0", | ||||
|                 "@sentry/minimal": "5.29.0", | ||||
|                 "@sentry/types": "5.29.0", | ||||
|                 "@sentry/utils": "5.29.0", | ||||
|                 "@sentry/hub": "5.29.2", | ||||
|                 "@sentry/minimal": "5.29.2", | ||||
|                 "@sentry/types": "5.29.2", | ||||
|                 "@sentry/utils": "5.29.2", | ||||
|                 "tslib": "^1.9.3" | ||||
|             }, | ||||
|             "dependencies": { | ||||
| @ -179,12 +179,12 @@ | ||||
|             } | ||||
|         }, | ||||
|         "@sentry/hub": { | ||||
|             "version": "5.29.0", | ||||
|             "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.29.0.tgz", | ||||
|             "integrity": "sha512-kcDPQsRG4cFdmqDh+TzjeO7lWYxU8s1dZYAbbl1J4uGKmhNB0J7I4ak4SGwTsXLY6fhbierxr6PRaoNojCxjPw==", | ||||
|             "version": "5.29.2", | ||||
|             "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.29.2.tgz", | ||||
|             "integrity": "sha512-LaAIo2hwUk9ykeh9RF0cwLy6IRw+DjEee8l1HfEaDFUM6TPGlNNGObMJNXb9/95jzWp7jWwOpQjoIE3jepdQJQ==", | ||||
|             "requires": { | ||||
|                 "@sentry/types": "5.29.0", | ||||
|                 "@sentry/utils": "5.29.0", | ||||
|                 "@sentry/types": "5.29.2", | ||||
|                 "@sentry/utils": "5.29.2", | ||||
|                 "tslib": "^1.9.3" | ||||
|             }, | ||||
|             "dependencies": { | ||||
| @ -196,12 +196,12 @@ | ||||
|             } | ||||
|         }, | ||||
|         "@sentry/minimal": { | ||||
|             "version": "5.29.0", | ||||
|             "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.29.0.tgz", | ||||
|             "integrity": "sha512-nhXofdjtO41/caiF1wk1oT3p/QuhOZDYdF/b29DoD2MiAMK9IjhhOXI/gqaRpDKkXlDvd95fDTcx4t/MqqcKXA==", | ||||
|             "version": "5.29.2", | ||||
|             "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.29.2.tgz", | ||||
|             "integrity": "sha512-0aINSm8fGA1KyM7PavOBe1GDZDxrvnKt+oFnU0L+bTcw8Lr+of+v6Kwd97rkLRNOLw621xP076dL/7LSIzMuhw==", | ||||
|             "requires": { | ||||
|                 "@sentry/hub": "5.29.0", | ||||
|                 "@sentry/types": "5.29.0", | ||||
|                 "@sentry/hub": "5.29.2", | ||||
|                 "@sentry/types": "5.29.2", | ||||
|                 "tslib": "^1.9.3" | ||||
|             }, | ||||
|             "dependencies": { | ||||
| @ -213,48 +213,48 @@ | ||||
|             } | ||||
|         }, | ||||
|         "@sentry/tracing": { | ||||
|             "version": "5.29.0", | ||||
|             "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-5.29.0.tgz", | ||||
|             "integrity": "sha512-2ZITUH7Eur7IkmRAd5gw8Xt2Sfc28btCnT7o2P2J8ZPD65e99ATqjxXPokx0+6zEkTsstIDD3mbyuwkpbuvuTA==", | ||||
|             "version": "5.29.2", | ||||
|             "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-5.29.2.tgz", | ||||
|             "integrity": "sha512-iumYbVRpvoU3BUuIooxibydeaOOjl5ysc+mzsqhRs2NGW/C3uKAsFXdvyNfqt3bxtRQwJEhwJByLP2u3pLThpw==", | ||||
|             "requires": { | ||||
|                 "@sentry/hub": "5.29.0", | ||||
|                 "@sentry/minimal": "5.29.0", | ||||
|                 "@sentry/types": "5.29.0", | ||||
|                 "@sentry/utils": "5.29.0", | ||||
|                 "@sentry/hub": "5.29.2", | ||||
|                 "@sentry/minimal": "5.29.2", | ||||
|                 "@sentry/types": "5.29.2", | ||||
|                 "@sentry/utils": "5.29.2", | ||||
|                 "tslib": "^1.9.3" | ||||
|             }, | ||||
|             "dependencies": { | ||||
|                 "@sentry/hub": { | ||||
|                     "version": "5.29.0", | ||||
|                     "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.29.0.tgz", | ||||
|                     "integrity": "sha512-kcDPQsRG4cFdmqDh+TzjeO7lWYxU8s1dZYAbbl1J4uGKmhNB0J7I4ak4SGwTsXLY6fhbierxr6PRaoNojCxjPw==", | ||||
|                     "version": "5.29.2", | ||||
|                     "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.29.2.tgz", | ||||
|                     "integrity": "sha512-LaAIo2hwUk9ykeh9RF0cwLy6IRw+DjEee8l1HfEaDFUM6TPGlNNGObMJNXb9/95jzWp7jWwOpQjoIE3jepdQJQ==", | ||||
|                     "requires": { | ||||
|                         "@sentry/types": "5.29.0", | ||||
|                         "@sentry/utils": "5.29.0", | ||||
|                         "@sentry/types": "5.29.2", | ||||
|                         "@sentry/utils": "5.29.2", | ||||
|                         "tslib": "^1.9.3" | ||||
|                     } | ||||
|                 }, | ||||
|                 "@sentry/minimal": { | ||||
|                     "version": "5.29.0", | ||||
|                     "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.29.0.tgz", | ||||
|                     "integrity": "sha512-nhXofdjtO41/caiF1wk1oT3p/QuhOZDYdF/b29DoD2MiAMK9IjhhOXI/gqaRpDKkXlDvd95fDTcx4t/MqqcKXA==", | ||||
|                     "version": "5.29.2", | ||||
|                     "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.29.2.tgz", | ||||
|                     "integrity": "sha512-0aINSm8fGA1KyM7PavOBe1GDZDxrvnKt+oFnU0L+bTcw8Lr+of+v6Kwd97rkLRNOLw621xP076dL/7LSIzMuhw==", | ||||
|                     "requires": { | ||||
|                         "@sentry/hub": "5.29.0", | ||||
|                         "@sentry/types": "5.29.0", | ||||
|                         "@sentry/hub": "5.29.2", | ||||
|                         "@sentry/types": "5.29.2", | ||||
|                         "tslib": "^1.9.3" | ||||
|                     } | ||||
|                 }, | ||||
|                 "@sentry/types": { | ||||
|                     "version": "5.29.0", | ||||
|                     "resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.29.0.tgz", | ||||
|                     "integrity": "sha512-iDkxT/9sT3UF+Xb+JyLjZ5caMXsgLfRyV9VXQEiR2J6mgpMielj184d9jeF3bm/VMuAf/VFFqrHlcVsVgmrrMw==" | ||||
|                     "version": "5.29.2", | ||||
|                     "resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.29.2.tgz", | ||||
|                     "integrity": "sha512-dM9wgt8wy4WRty75QkqQgrw9FV9F+BOMfmc0iaX13Qos7i6Qs2Q0dxtJ83SoR4YGtW8URaHzlDtWlGs5egBiMA==" | ||||
|                 }, | ||||
|                 "@sentry/utils": { | ||||
|                     "version": "5.29.0", | ||||
|                     "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.29.0.tgz", | ||||
|                     "integrity": "sha512-b2B1gshw2u3EHlAi84PuI5sfmLKXW1z9enMMhNuuNT/CoRp+g5kMAcUv/qYTws7UNnYSvTuVGuZG30v1e0hP9A==", | ||||
|                     "version": "5.29.2", | ||||
|                     "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.29.2.tgz", | ||||
|                     "integrity": "sha512-nEwQIDjtFkeE4k6yIk4Ka5XjGRklNLThWLs2xfXlL7uwrYOH2B9UBBOOIRUraBm/g/Xrra3xsam/kRxuiwtXZQ==", | ||||
|                     "requires": { | ||||
|                         "@sentry/types": "5.29.0", | ||||
|                         "@sentry/types": "5.29.2", | ||||
|                         "tslib": "^1.9.3" | ||||
|                     } | ||||
|                 }, | ||||
| @ -266,16 +266,16 @@ | ||||
|             } | ||||
|         }, | ||||
|         "@sentry/types": { | ||||
|             "version": "5.29.0", | ||||
|             "resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.29.0.tgz", | ||||
|             "integrity": "sha512-iDkxT/9sT3UF+Xb+JyLjZ5caMXsgLfRyV9VXQEiR2J6mgpMielj184d9jeF3bm/VMuAf/VFFqrHlcVsVgmrrMw==" | ||||
|             "version": "5.29.2", | ||||
|             "resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.29.2.tgz", | ||||
|             "integrity": "sha512-dM9wgt8wy4WRty75QkqQgrw9FV9F+BOMfmc0iaX13Qos7i6Qs2Q0dxtJ83SoR4YGtW8URaHzlDtWlGs5egBiMA==" | ||||
|         }, | ||||
|         "@sentry/utils": { | ||||
|             "version": "5.29.0", | ||||
|             "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.29.0.tgz", | ||||
|             "integrity": "sha512-b2B1gshw2u3EHlAi84PuI5sfmLKXW1z9enMMhNuuNT/CoRp+g5kMAcUv/qYTws7UNnYSvTuVGuZG30v1e0hP9A==", | ||||
|             "version": "5.29.2", | ||||
|             "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.29.2.tgz", | ||||
|             "integrity": "sha512-nEwQIDjtFkeE4k6yIk4Ka5XjGRklNLThWLs2xfXlL7uwrYOH2B9UBBOOIRUraBm/g/Xrra3xsam/kRxuiwtXZQ==", | ||||
|             "requires": { | ||||
|                 "@sentry/types": "5.29.0", | ||||
|                 "@sentry/types": "5.29.2", | ||||
|                 "tslib": "^1.9.3" | ||||
|             }, | ||||
|             "dependencies": { | ||||
| @ -287,9 +287,9 @@ | ||||
|             } | ||||
|         }, | ||||
|         "@types/chart.js": { | ||||
|             "version": "2.9.28", | ||||
|             "resolved": "https://registry.npmjs.org/@types/chart.js/-/chart.js-2.9.28.tgz", | ||||
|             "integrity": "sha512-9YYhsxRngRJb0dkuaU5BezkF+zvvVHnwdRw+rtlahtFb4zqNf9YSgWsOq+dLYeh0fqsWmHUYLR64eNigh02F+w==", | ||||
|             "version": "2.9.29", | ||||
|             "resolved": "https://registry.npmjs.org/@types/chart.js/-/chart.js-2.9.29.tgz", | ||||
|             "integrity": "sha512-WOZMitUU3gHDM0oQsCsVivX+oDsIki93szcTmmUPBm39cCvAELBjokjSDVOoA3xiIEbb+jp17z/3S2tIqruwOQ==", | ||||
|             "requires": { | ||||
|                 "moment": "^2.10.2" | ||||
|             } | ||||
| @ -393,156 +393,70 @@ | ||||
|             } | ||||
|         }, | ||||
|         "@typescript-eslint/eslint-plugin": { | ||||
|             "version": "4.9.1", | ||||
|             "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.9.1.tgz", | ||||
|             "integrity": "sha512-QRLDSvIPeI1pz5tVuurD+cStNR4sle4avtHhxA+2uyixWGFjKzJ+EaFVRW6dA/jOgjV5DTAjOxboQkRDE8cRlQ==", | ||||
|             "version": "4.10.0", | ||||
|             "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.10.0.tgz", | ||||
|             "integrity": "sha512-h6/V46o6aXpKRlarP1AiJEXuCJ7cMQdlpfMDrcllIgX3dFkLwEBTXAoNP98ZoOmqd1xvymMVRAI4e7yVvlzWEg==", | ||||
|             "dev": true, | ||||
|             "requires": { | ||||
|                 "@typescript-eslint/experimental-utils": "4.9.1", | ||||
|                 "@typescript-eslint/scope-manager": "4.9.1", | ||||
|                 "@typescript-eslint/experimental-utils": "4.10.0", | ||||
|                 "@typescript-eslint/scope-manager": "4.10.0", | ||||
|                 "debug": "^4.1.1", | ||||
|                 "functional-red-black-tree": "^1.0.1", | ||||
|                 "regexpp": "^3.0.0", | ||||
|                 "semver": "^7.3.2", | ||||
|                 "tsutils": "^3.17.1" | ||||
|             }, | ||||
|             "dependencies": { | ||||
|                 "@typescript-eslint/scope-manager": { | ||||
|                     "version": "4.9.1", | ||||
|                     "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.9.1.tgz", | ||||
|                     "integrity": "sha512-sa4L9yUfD/1sg9Kl8OxPxvpUcqxKXRjBeZxBuZSSV1v13hjfEJkn84n0An2hN8oLQ1PmEl2uA6FkI07idXeFgQ==", | ||||
|                     "dev": true, | ||||
|                     "requires": { | ||||
|                         "@typescript-eslint/types": "4.9.1", | ||||
|                         "@typescript-eslint/visitor-keys": "4.9.1" | ||||
|                     } | ||||
|                 }, | ||||
|                 "@typescript-eslint/types": { | ||||
|                     "version": "4.9.1", | ||||
|                     "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.9.1.tgz", | ||||
|                     "integrity": "sha512-fjkT+tXR13ks6Le7JiEdagnwEFc49IkOyys7ueWQ4O8k4quKPwPJudrwlVOJCUQhXo45PrfIvIarcrEjFTNwUA==", | ||||
|                     "dev": true | ||||
|                 }, | ||||
|                 "@typescript-eslint/visitor-keys": { | ||||
|                     "version": "4.9.1", | ||||
|                     "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.9.1.tgz", | ||||
|                     "integrity": "sha512-9gspzc6UqLQHd7lXQS7oWs+hrYggspv/rk6zzEMhCbYwPE/sF7oxo7GAjkS35Tdlt7wguIG+ViWCPtVZHz/ybQ==", | ||||
|                     "dev": true, | ||||
|                     "requires": { | ||||
|                         "@typescript-eslint/types": "4.9.1", | ||||
|                         "eslint-visitor-keys": "^2.0.0" | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         "@typescript-eslint/experimental-utils": { | ||||
|             "version": "4.9.1", | ||||
|             "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.9.1.tgz", | ||||
|             "integrity": "sha512-c3k/xJqk0exLFs+cWSJxIjqLYwdHCuLWhnpnikmPQD2+NGAx9KjLYlBDcSI81EArh9FDYSL6dslAUSwILeWOxg==", | ||||
|             "version": "4.10.0", | ||||
|             "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.10.0.tgz", | ||||
|             "integrity": "sha512-opX+7ai1sdWBOIoBgpVJrH5e89ra1KoLrJTz0UtWAa4IekkKmqDosk5r6xqRaNJfCXEfteW4HXQAwMdx+jjEmw==", | ||||
|             "dev": true, | ||||
|             "requires": { | ||||
|                 "@types/json-schema": "^7.0.3", | ||||
|                 "@typescript-eslint/scope-manager": "4.9.1", | ||||
|                 "@typescript-eslint/types": "4.9.1", | ||||
|                 "@typescript-eslint/typescript-estree": "4.9.1", | ||||
|                 "@typescript-eslint/scope-manager": "4.10.0", | ||||
|                 "@typescript-eslint/types": "4.10.0", | ||||
|                 "@typescript-eslint/typescript-estree": "4.10.0", | ||||
|                 "eslint-scope": "^5.0.0", | ||||
|                 "eslint-utils": "^2.0.0" | ||||
|             }, | ||||
|             "dependencies": { | ||||
|                 "@typescript-eslint/scope-manager": { | ||||
|                     "version": "4.9.1", | ||||
|                     "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.9.1.tgz", | ||||
|                     "integrity": "sha512-sa4L9yUfD/1sg9Kl8OxPxvpUcqxKXRjBeZxBuZSSV1v13hjfEJkn84n0An2hN8oLQ1PmEl2uA6FkI07idXeFgQ==", | ||||
|                     "dev": true, | ||||
|                     "requires": { | ||||
|                         "@typescript-eslint/types": "4.9.1", | ||||
|                         "@typescript-eslint/visitor-keys": "4.9.1" | ||||
|                     } | ||||
|                 }, | ||||
|                 "@typescript-eslint/types": { | ||||
|                     "version": "4.9.1", | ||||
|                     "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.9.1.tgz", | ||||
|                     "integrity": "sha512-fjkT+tXR13ks6Le7JiEdagnwEFc49IkOyys7ueWQ4O8k4quKPwPJudrwlVOJCUQhXo45PrfIvIarcrEjFTNwUA==", | ||||
|                     "dev": true | ||||
|                 }, | ||||
|                 "@typescript-eslint/typescript-estree": { | ||||
|                     "version": "4.9.1", | ||||
|                     "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.9.1.tgz", | ||||
|                     "integrity": "sha512-bzP8vqwX6Vgmvs81bPtCkLtM/Skh36NE6unu6tsDeU/ZFoYthlTXbBmpIrvosgiDKlWTfb2ZpPELHH89aQjeQw==", | ||||
|                     "dev": true, | ||||
|                     "requires": { | ||||
|                         "@typescript-eslint/types": "4.9.1", | ||||
|                         "@typescript-eslint/visitor-keys": "4.9.1", | ||||
|                         "debug": "^4.1.1", | ||||
|                         "globby": "^11.0.1", | ||||
|                         "is-glob": "^4.0.1", | ||||
|                         "lodash": "^4.17.15", | ||||
|                         "semver": "^7.3.2", | ||||
|                         "tsutils": "^3.17.1" | ||||
|                     } | ||||
|                 }, | ||||
|                 "@typescript-eslint/visitor-keys": { | ||||
|                     "version": "4.9.1", | ||||
|                     "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.9.1.tgz", | ||||
|                     "integrity": "sha512-9gspzc6UqLQHd7lXQS7oWs+hrYggspv/rk6zzEMhCbYwPE/sF7oxo7GAjkS35Tdlt7wguIG+ViWCPtVZHz/ybQ==", | ||||
|                     "dev": true, | ||||
|                     "requires": { | ||||
|                         "@typescript-eslint/types": "4.9.1", | ||||
|                         "eslint-visitor-keys": "^2.0.0" | ||||
|                     } | ||||
|                 }, | ||||
|                 "globby": { | ||||
|                     "version": "11.0.1", | ||||
|                     "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz", | ||||
|                     "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==", | ||||
|                     "dev": true, | ||||
|                     "requires": { | ||||
|                         "array-union": "^2.1.0", | ||||
|                         "dir-glob": "^3.0.1", | ||||
|                         "fast-glob": "^3.1.1", | ||||
|                         "ignore": "^5.1.4", | ||||
|                         "merge2": "^1.3.0", | ||||
|                         "slash": "^3.0.0" | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         "@typescript-eslint/parser": { | ||||
|             "version": "4.9.1", | ||||
|             "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.9.1.tgz", | ||||
|             "integrity": "sha512-Gv2VpqiomvQ2v4UL+dXlQcZ8zCX4eTkoIW+1aGVWT6yTO+6jbxsw7yQl2z2pPl/4B9qa5JXeIbhJpONKjXIy3g==", | ||||
|             "version": "4.10.0", | ||||
|             "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.10.0.tgz", | ||||
|             "integrity": "sha512-amBvUUGBMadzCW6c/qaZmfr3t9PyevcSWw7hY2FuevdZVp5QPw/K76VSQ5Sw3BxlgYCHZcK6DjIhSZK0PQNsQg==", | ||||
|             "dev": true, | ||||
|             "requires": { | ||||
|                 "@typescript-eslint/scope-manager": "4.9.1", | ||||
|                 "@typescript-eslint/types": "4.9.1", | ||||
|                 "@typescript-eslint/typescript-estree": "4.9.1", | ||||
|                 "@typescript-eslint/scope-manager": "4.10.0", | ||||
|                 "@typescript-eslint/types": "4.10.0", | ||||
|                 "@typescript-eslint/typescript-estree": "4.10.0", | ||||
|                 "debug": "^4.1.1" | ||||
|             } | ||||
|         }, | ||||
|         "@typescript-eslint/scope-manager": { | ||||
|             "version": "4.9.1", | ||||
|             "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.9.1.tgz", | ||||
|             "integrity": "sha512-sa4L9yUfD/1sg9Kl8OxPxvpUcqxKXRjBeZxBuZSSV1v13hjfEJkn84n0An2hN8oLQ1PmEl2uA6FkI07idXeFgQ==", | ||||
|             "version": "4.10.0", | ||||
|             "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.10.0.tgz", | ||||
|             "integrity": "sha512-WAPVw35P+fcnOa8DEic0tQUhoJJsgt+g6DEcz257G7vHFMwmag58EfowdVbiNcdfcV27EFR0tUBVXkDoIvfisQ==", | ||||
|             "dev": true, | ||||
|             "requires": { | ||||
|                 "@typescript-eslint/types": "4.9.1", | ||||
|                 "@typescript-eslint/visitor-keys": "4.9.1" | ||||
|                 "@typescript-eslint/types": "4.10.0", | ||||
|                 "@typescript-eslint/visitor-keys": "4.10.0" | ||||
|             } | ||||
|         }, | ||||
|         "@typescript-eslint/types": { | ||||
|             "version": "4.9.1", | ||||
|             "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.9.1.tgz", | ||||
|             "integrity": "sha512-fjkT+tXR13ks6Le7JiEdagnwEFc49IkOyys7ueWQ4O8k4quKPwPJudrwlVOJCUQhXo45PrfIvIarcrEjFTNwUA==", | ||||
|             "version": "4.10.0", | ||||
|             "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.10.0.tgz", | ||||
|             "integrity": "sha512-+dt5w1+Lqyd7wIPMa4XhJxUuE8+YF+vxQ6zxHyhLGHJjHiunPf0wSV8LtQwkpmAsRi1lEOoOIR30FG5S2HS33g==", | ||||
|             "dev": true | ||||
|         }, | ||||
|         "@typescript-eslint/typescript-estree": { | ||||
|             "version": "4.9.1", | ||||
|             "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.9.1.tgz", | ||||
|             "integrity": "sha512-bzP8vqwX6Vgmvs81bPtCkLtM/Skh36NE6unu6tsDeU/ZFoYthlTXbBmpIrvosgiDKlWTfb2ZpPELHH89aQjeQw==", | ||||
|             "version": "4.10.0", | ||||
|             "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.10.0.tgz", | ||||
|             "integrity": "sha512-mGK0YRp9TOk6ZqZ98F++bW6X5kMTzCRROJkGXH62d2azhghmq+1LNLylkGe6uGUOQzD452NOAEth5VAF6PDo5g==", | ||||
|             "dev": true, | ||||
|             "requires": { | ||||
|                 "@typescript-eslint/types": "4.9.1", | ||||
|                 "@typescript-eslint/visitor-keys": "4.9.1", | ||||
|                 "@typescript-eslint/types": "4.10.0", | ||||
|                 "@typescript-eslint/visitor-keys": "4.10.0", | ||||
|                 "debug": "^4.1.1", | ||||
|                 "globby": "^11.0.1", | ||||
|                 "is-glob": "^4.0.1", | ||||
| @ -568,12 +482,12 @@ | ||||
|             } | ||||
|         }, | ||||
|         "@typescript-eslint/visitor-keys": { | ||||
|             "version": "4.9.1", | ||||
|             "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.9.1.tgz", | ||||
|             "integrity": "sha512-9gspzc6UqLQHd7lXQS7oWs+hrYggspv/rk6zzEMhCbYwPE/sF7oxo7GAjkS35Tdlt7wguIG+ViWCPtVZHz/ybQ==", | ||||
|             "version": "4.10.0", | ||||
|             "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.10.0.tgz", | ||||
|             "integrity": "sha512-hPyz5qmDMuZWFtHZkjcCpkAKHX8vdu1G3YsCLEd25ryZgnJfj6FQuJ5/O7R+dB1ueszilJmAFMtlU4CA6se3Jg==", | ||||
|             "dev": true, | ||||
|             "requires": { | ||||
|                 "@typescript-eslint/types": "4.9.1", | ||||
|                 "@typescript-eslint/types": "4.10.0", | ||||
|                 "eslint-visitor-keys": "^2.0.0" | ||||
|             } | ||||
|         }, | ||||
| @ -1215,9 +1129,9 @@ | ||||
|             "dev": true | ||||
|         }, | ||||
|         "eslint-plugin-lit": { | ||||
|             "version": "1.2.4", | ||||
|             "resolved": "https://registry.npmjs.org/eslint-plugin-lit/-/eslint-plugin-lit-1.2.4.tgz", | ||||
|             "integrity": "sha512-LfmtuaW9ZcE8R2ji5cMj+SG5bSjEY+IBexuAOKKE+IUB8b6N0AnhVATbfaAX5V2KibeKvIBit2Xpo3QabpeiuA==", | ||||
|             "version": "1.3.0", | ||||
|             "resolved": "https://registry.npmjs.org/eslint-plugin-lit/-/eslint-plugin-lit-1.3.0.tgz", | ||||
|             "integrity": "sha512-fy6Lr5vYI3kvCYaDXA20lwyKAp1keS9UjR5ntj8U2TeV+1yUta3S7xxXe+rABKRPbcNzi1ZvQLE1LmNKc9yr4Q==", | ||||
|             "dev": true, | ||||
|             "requires": { | ||||
|                 "parse5": "^6.0.1", | ||||
| @ -2680,9 +2594,9 @@ | ||||
|             } | ||||
|         }, | ||||
|         "rollup": { | ||||
|             "version": "2.34.2", | ||||
|             "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.34.2.tgz", | ||||
|             "integrity": "sha512-mvtQLqu3cNeoctS+kZ09iOPxrc1P1/Bt1z15enuQ5feyKOdM3MJAVFjjsygurDpSWn530xB4AlA83TWIzRstXA==", | ||||
|             "version": "2.35.1", | ||||
|             "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.35.1.tgz", | ||||
|             "integrity": "sha512-q5KxEyWpprAIcainhVy6HfRttD9kutQpHbeqDTWnqAFNJotiojetK6uqmcydNMymBEtC4I8bCYR+J3mTMqeaUA==", | ||||
|             "requires": { | ||||
|                 "fsevents": "~2.1.2" | ||||
|             } | ||||
| @ -3317,9 +3231,9 @@ | ||||
|             "dev": true | ||||
|         }, | ||||
|         "typescript": { | ||||
|             "version": "4.1.2", | ||||
|             "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.2.tgz", | ||||
|             "integrity": "sha512-thGloWsGH3SOxv1SoY7QojKi0tc+8FnOmiarEGMbd/lar7QOEd3hvlx3Fp5y6FlDUGl9L+pd4n2e+oToGMmhRQ==", | ||||
|             "version": "4.1.3", | ||||
|             "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.3.tgz", | ||||
|             "integrity": "sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==", | ||||
|             "dev": true | ||||
|         }, | ||||
|         "uglify-js": { | ||||
|  | ||||
| @ -8,35 +8,35 @@ | ||||
|     }, | ||||
|     "dependencies": { | ||||
|         "@fortawesome/fontawesome-free": "^5.15.1", | ||||
|         "@patternfly/patternfly": "^4.65.6", | ||||
|         "@sentry/browser": "^5.29.0", | ||||
|         "@sentry/tracing": "^5.29.0", | ||||
|         "@types/chart.js": "^2.9.28", | ||||
|         "@patternfly/patternfly": "^4.70.2", | ||||
|         "@sentry/browser": "^5.29.2", | ||||
|         "@sentry/tracing": "^5.29.2", | ||||
|         "@types/chart.js": "^2.9.29", | ||||
|         "@types/codemirror": "0.0.102", | ||||
|         "chart.js": "^2.9.4", | ||||
|         "codemirror": "^5.58.3", | ||||
|         "construct-style-sheets-polyfill": "^2.4.3", | ||||
|         "lit-element": "^2.4.0", | ||||
|         "lit-html": "^1.3.0", | ||||
|         "rollup": "^2.34.2", | ||||
|         "rollup": "^2.35.1", | ||||
|         "rollup-plugin-copy": "^3.3.0", | ||||
|         "rollup-plugin-cssimport": "^1.0.2", | ||||
|         "rollup-plugin-external-globals": "^0.6.1", | ||||
|         "tslib": "^2.0.3" | ||||
|     }, | ||||
|     "devDependencies": { | ||||
|         "@rollup/plugin-typescript": "^8.0.0", | ||||
|         "@typescript-eslint/eslint-plugin": "^4.9.1", | ||||
|         "@typescript-eslint/parser": "^4.9.1", | ||||
|         "@rollup/plugin-typescript": "^8.1.0", | ||||
|         "@typescript-eslint/eslint-plugin": "^4.10.0", | ||||
|         "@typescript-eslint/parser": "^4.10.0", | ||||
|         "eslint": "^7.15.0", | ||||
|         "eslint-config-google": "^0.14.0", | ||||
|         "eslint-plugin-lit": "^1.2.4", | ||||
|         "eslint-plugin-lit": "^1.3.0", | ||||
|         "rollup-plugin-commonjs": "^10.1.0", | ||||
|         "rollup-plugin-minify-html-literals": "^1.2.5", | ||||
|         "rollup-plugin-node-resolve": "^5.2.0", | ||||
|         "rollup-plugin-sourcemaps": "^0.6.3", | ||||
|         "rollup-plugin-terser": "^7.0.2", | ||||
|         "ts-lit-plugin": "^1.2.1", | ||||
|         "typescript": "^4.1.2" | ||||
|         "typescript": "^4.1.3" | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| import { DefaultClient, PBResponse, QueryArguments } from "./client"; | ||||
| import { DefaultClient, PBResponse, QueryArguments } from "./Client"; | ||||
| 
 | ||||
| export class Application { | ||||
|     pk: string; | ||||
| @ -1,4 +1,4 @@ | ||||
| import { NotFoundError, RequestError } from "./errors"; | ||||
| import { NotFoundError, RequestError } from "./Error"; | ||||
| 
 | ||||
| export const VERSION = "v2beta"; | ||||
| 
 | ||||
| @ -1,4 +1,4 @@ | ||||
| import { DefaultClient } from "./client"; | ||||
| import { DefaultClient } from "./Client"; | ||||
| import * as Sentry from "@sentry/browser"; | ||||
| import { Integrations } from "@sentry/tracing"; | ||||
| import { VERSION } from "../constants"; | ||||
| @ -1,4 +1,4 @@ | ||||
| import { DefaultClient } from "./client"; | ||||
| import { DefaultClient } from "./Client"; | ||||
| 
 | ||||
| export class AuditEvent { | ||||
|     //audit/events/top_per_user/?filter_action=authorize_application
 | ||||
| @ -1,4 +1,4 @@ | ||||
| import { DefaultClient, PBResponse, QueryArguments } from "./client"; | ||||
| import { DefaultClient, PBResponse, QueryArguments } from "./Client"; | ||||
| 
 | ||||
| export enum FlowDesignation { | ||||
|     Authentication = "authentication", | ||||
| @ -33,6 +33,12 @@ export class Flow { | ||||
|     static list(filter?: QueryArguments): Promise<PBResponse<Flow>> { | ||||
|         return DefaultClient.fetch<PBResponse<Flow>>(["flows", "instances"], filter); | ||||
|     } | ||||
| 
 | ||||
|     static cached(): Promise<number> { | ||||
|         return DefaultClient.fetch<PBResponse<Flow>>(["flows", "cached"]).then(r => { | ||||
|             return r.pagination.count; | ||||
|         }); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| export class Stage { | ||||
							
								
								
									
										24
									
								
								web/src/api/Policies.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								web/src/api/Policies.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | ||||
| import { DefaultClient, PBResponse, QueryArguments } from "./Client"; | ||||
|  | ||||
| export class Policy { | ||||
|     pk: string; | ||||
|     name: string; | ||||
|  | ||||
|     constructor() { | ||||
|         throw Error(); | ||||
|     } | ||||
|  | ||||
|     static get(pk: string): Promise<Policy> { | ||||
|         return DefaultClient.fetch<Policy>(["policies", "all", pk]); | ||||
|     } | ||||
|  | ||||
|     static list(filter?: QueryArguments): Promise<PBResponse<Policy>> { | ||||
|         return DefaultClient.fetch<PBResponse<Policy>>(["policies", "all"], filter); | ||||
|     } | ||||
|  | ||||
|     static cached(): Promise<number> { | ||||
|         return DefaultClient.fetch<PBResponse<Policy>>(["policies", "cached"]).then(r => { | ||||
|             return r.pagination.count; | ||||
|         }); | ||||
|     } | ||||
| } | ||||
| @ -1,10 +1,5 @@ | ||||
| import { DefaultClient, PBResponse, QueryArguments } from "./client"; | ||||
| 
 | ||||
| export interface Policy { | ||||
|     pk: string; | ||||
|     name: string; | ||||
|     [key: string]: unknown; | ||||
| } | ||||
| import { DefaultClient, PBResponse, QueryArguments } from "./Client"; | ||||
| import { Policy } from "./Policies"; | ||||
| 
 | ||||
| export class PolicyBinding { | ||||
|     pk: string; | ||||
							
								
								
									
										19
									
								
								web/src/api/Providers.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								web/src/api/Providers.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | ||||
| import { DefaultClient, PBResponse, QueryArguments } from "./Client"; | ||||
|  | ||||
| export class Provider { | ||||
|     pk: number; | ||||
|     name: string; | ||||
|     authorization_flow: string; | ||||
|  | ||||
|     constructor() { | ||||
|         throw Error(); | ||||
|     } | ||||
|  | ||||
|     static get(slug: string): Promise<Provider> { | ||||
|         return DefaultClient.fetch<Provider>(["providers", "all", slug]); | ||||
|     } | ||||
|  | ||||
|     static list(filter?: QueryArguments): Promise<PBResponse<Provider>> { | ||||
|         return DefaultClient.fetch<PBResponse<Provider>>(["providers", "all"], filter); | ||||
|     } | ||||
| } | ||||
| @ -1,4 +1,4 @@ | ||||
| import { DefaultClient, PBResponse, QueryArguments } from "./client"; | ||||
| import { DefaultClient, PBResponse, QueryArguments } from "./Client"; | ||||
| 
 | ||||
| export class Source { | ||||
|     pk: string; | ||||
| @ -1,4 +1,4 @@ | ||||
| import { DefaultClient } from "./client"; | ||||
| import { DefaultClient } from "./Client"; | ||||
| 
 | ||||
| interface TokenResponse { | ||||
|     key: string; | ||||
| @ -1,4 +1,4 @@ | ||||
| import { DefaultClient, PBResponse } from "./client"; | ||||
| import { DefaultClient, PBResponse } from "./Client"; | ||||
| 
 | ||||
| let _globalMePromise: Promise<User>; | ||||
| 
 | ||||
							
								
								
									
										17
									
								
								web/src/api/Versions.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								web/src/api/Versions.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | ||||
| import { DefaultClient } from "./Client"; | ||||
|  | ||||
| export class Version { | ||||
|  | ||||
|     version_current: string; | ||||
|     version_latest: string; | ||||
|     outdated: boolean; | ||||
|  | ||||
|     constructor() { | ||||
|         throw Error(); | ||||
|     } | ||||
|  | ||||
|     static get(): Promise<Version> { | ||||
|         return DefaultClient.fetch<Version>(["admin", "version"]); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @ -1,20 +0,0 @@ | ||||
| import { DefaultClient } from "./client"; | ||||
|  | ||||
| export class AdminOverview { | ||||
|     version: string; | ||||
|     version_latest: string; | ||||
|     worker_count: number; | ||||
|     providers_without_application: number; | ||||
|     policies_without_binding: number; | ||||
|     cached_policies: number; | ||||
|     cached_flows: number; | ||||
|  | ||||
|     constructor() { | ||||
|         throw Error(); | ||||
|     } | ||||
|  | ||||
|     static get(): Promise<AdminOverview> { | ||||
|         return DefaultClient.fetch<AdminOverview>(["admin", "overview"]); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @ -5,11 +5,6 @@ html { | ||||
|     --pf-c-nav__link--PaddingLeft: 0.5rem; | ||||
| } | ||||
|  | ||||
| /* Fix patternfly sidebar and header with open Modal */ | ||||
| .pf-c-page__sidebar { | ||||
|     z-index: 0; | ||||
| } | ||||
|  | ||||
| .pf-c-page__header { | ||||
|     z-index: 0; | ||||
| } | ||||
| @ -162,10 +157,12 @@ select[multiple] { | ||||
|         background-color: var(--ak-dark-background-light); | ||||
|         color: var(--ak-dark-foreground); | ||||
|     } | ||||
|     .pf-m-tertiary, | ||||
|     .pf-c-button.pf-m-tertiary { | ||||
|         --pf-c-button--after--BorderColor: var(--ak-dark-foreground-darker); | ||||
|         color: var(--ak-dark-foreground-darker); | ||||
|     } | ||||
|     .pf-m-tertiary:hover, | ||||
|     .pf-c-button.pf-m-tertiary:hover { | ||||
|         --pf-c-button--after--BorderColor: var(--ak-dark-background-lighter); | ||||
|     } | ||||
| @ -197,6 +194,9 @@ select[multiple] { | ||||
|     .pf-c-login__main { | ||||
|         background-color: var(--ak-dark-background); | ||||
|     } | ||||
|     .pf-c-login__main-body { | ||||
|         color: var(--ak-dark-foreground); | ||||
|     } | ||||
|     .pf-c-login__main-footer-links-item-link > img { | ||||
|         filter: invert(1); | ||||
|     } | ||||
|  | ||||
| @ -28,4 +28,4 @@ export const ColorStyles = css` | ||||
|         background-color: var(--pf-global--danger-color--100); | ||||
|     } | ||||
| `; | ||||
| export const VERSION = "0.13.0-rc4"; | ||||
| export const VERSION = "0.13.3-stable"; | ||||
|  | ||||
| @ -3,7 +3,7 @@ import { css, CSSResult, customElement, html, LitElement, property, TemplateResu | ||||
| import GlobalsStyle from "@patternfly/patternfly/base/patternfly-globals.css"; | ||||
| // @ts-ignore | ||||
| import ButtonStyle from "@patternfly/patternfly/components/Button/button.css"; | ||||
| import { tokenByIdentifier } from "../../api/token"; | ||||
| import { tokenByIdentifier } from "../../api/Tokens"; | ||||
| import { ColorStyles, ERROR_CLASS, PRIMARY_CLASS, SUCCESS_CLASS } from "../../constants"; | ||||
|  | ||||
| @customElement("ak-token-copy-button") | ||||
|  | ||||
| @ -2,6 +2,7 @@ import { gettext } from "django"; | ||||
| import { css, CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element"; | ||||
| import { ifDefined } from "lit-html/directives/if-defined"; | ||||
| import { COMMON_STYLES } from "../../common/styles"; | ||||
| import { ColorStyles } from "../../constants"; | ||||
|  | ||||
| @customElement("ak-aggregate-card") | ||||
| export class AggregateCard extends LitElement { | ||||
| @ -24,22 +25,26 @@ export class AggregateCard extends LitElement { | ||||
|                 text-align: center; | ||||
|                 color: var(--pf-global--Color--100); | ||||
|             } | ||||
|         `]); | ||||
|         `, ColorStyles]); | ||||
|     } | ||||
|  | ||||
|     renderInner(): TemplateResult { | ||||
|         return html`<slot></slot>`; | ||||
|     } | ||||
|  | ||||
|     renderHeaderLink(): TemplateResult { | ||||
|         return html`${this.headerLink ? html`<a href="${this.headerLink}"> | ||||
|             <i class="fa fa-external-link-alt"> </i> | ||||
|         </a>` : ""}`; | ||||
|     } | ||||
|  | ||||
|     render(): TemplateResult { | ||||
|         return html`<div class="pf-c-card pf-c-card-aggregate"> | ||||
|             <div class="pf-c-card__header pf-l-flex pf-m-justify-content-space-between"> | ||||
|                 <div class="pf-c-card__header-main"> | ||||
|                     <i class="${ifDefined(this.icon)}"></i> ${this.header ? gettext(this.header) : ""} | ||||
|                 </div> | ||||
|                 ${this.headerLink ? html`<a href="${this.headerLink}"> | ||||
|                     <i class="fa fa-external-link-alt"> </i> | ||||
|                 </a>` : ""} | ||||
|                 ${this.renderHeaderLink()} | ||||
|             </div> | ||||
|             <div class="pf-c-card__body center-value"> | ||||
|                 ${this.renderInner()} | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| import { gettext } from "django"; | ||||
| import { LitElement, html, customElement, TemplateResult, property } from "lit-element"; | ||||
| import { DefaultClient } from "../../api/client"; | ||||
| import { DefaultClient } from "../../api/Client"; | ||||
| import "./Message"; | ||||
| import { APIMessage } from "./Message"; | ||||
|  | ||||
|  | ||||
| @ -1,8 +1,8 @@ | ||||
| import { gettext } from "django"; | ||||
| import { customElement, html, property, TemplateResult } from "lit-element"; | ||||
| import { PBResponse } from "../../api/client"; | ||||
| import { PolicyBinding } from "../../api/policy_binding"; | ||||
| import { PBResponse } from "../../api/Client"; | ||||
| import { Table } from "../../elements/table/Table"; | ||||
| import { PolicyBinding } from "../../api/PolicyBindings"; | ||||
|  | ||||
| import "../../elements/Tabs"; | ||||
| import "../../elements/AdminLoginsChart"; | ||||
|  | ||||
| @ -65,6 +65,32 @@ export class SidebarItem { | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     async render(activePath: string): Promise<TemplateResult> { | ||||
|         if (this.condition) { | ||||
|             const result = await this.condition(); | ||||
|             if (!result) { | ||||
|                 return html``; | ||||
|             } | ||||
|         } | ||||
|         return html` <li class="pf-c-nav__item ${this.hasChildren() ? "pf-m-expandable pf-m-expanded" : ""}"> | ||||
|             ${this.path ? | ||||
|         html`<a href="#${this.path}" class="pf-c-nav__link ${this.isActive(activePath) ? "pf-m-current" : ""}"> | ||||
|                         ${this.name} | ||||
|                     </a>` : | ||||
|         html`<a class="pf-c-nav__link" aria-expanded="true"> | ||||
|                         ${this.name} | ||||
|                         <span class="pf-c-nav__toggle"> | ||||
|                             <i class="fas fa-angle-right" aria-hidden="true"></i> | ||||
|                         </span> | ||||
|                     </a> | ||||
|                     <section class="pf-c-nav__subnav"> | ||||
|                         <ul class="pf-c-nav__simple-list"> | ||||
|                             ${this._children.map((i) => until(i.render(activePath), html``))} | ||||
|                         </ul> | ||||
|                     </section>`} | ||||
|         </li>`; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @customElement("ak-sidebar") | ||||
| @ -118,37 +144,11 @@ export class Sidebar extends LitElement { | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     async renderItem(item: SidebarItem): Promise<TemplateResult> { | ||||
|         if (item.condition) { | ||||
|             const result = await item.condition(); | ||||
|             if (!result) { | ||||
|                 return html``; | ||||
|             } | ||||
|         } | ||||
|         return html` <li class="pf-c-nav__item ${item.hasChildren() ? "pf-m-expandable pf-m-expanded" : ""}"> | ||||
|             ${item.path ? | ||||
|         html`<a href="#${item.path}" class="pf-c-nav__link ${item.isActive(this.activePath) ? "pf-m-current": ""}"> | ||||
|                         ${item.name} | ||||
|                     </a>` : | ||||
|         html`<a class="pf-c-nav__link" aria-expanded="true"> | ||||
|                         ${item.name} | ||||
|                         <span class="pf-c-nav__toggle"> | ||||
|                             <i class="fas fa-angle-right" aria-hidden="true"></i> | ||||
|                         </span> | ||||
|                     </a> | ||||
|                     <section class="pf-c-nav__subnav"> | ||||
|                         <ul class="pf-c-nav__simple-list"> | ||||
|                             ${item._children.map((i) => until(this.renderItem(i), html``))} | ||||
|                         </ul> | ||||
|                     </section>`} | ||||
|         </li>`; | ||||
|     } | ||||
|  | ||||
|     render(): TemplateResult { | ||||
|         return html`<nav class="pf-c-nav" aria-label="Global"> | ||||
|             <ak-sidebar-brand></ak-sidebar-brand> | ||||
|             <ul class="pf-c-nav__list"> | ||||
|                 ${this.items.map((i) => until(this.renderItem(i), html``))} | ||||
|                 ${this.items.map((i) => until(i.render(this.activePath), html``))} | ||||
|             </ul> | ||||
|             <ak-sidebar-user></ak-sidebar-user> | ||||
|         </nav>`; | ||||
|  | ||||
| @ -3,7 +3,7 @@ import { css, CSSResult, customElement, html, LitElement, property, TemplateResu | ||||
| import PageStyle from "@patternfly/patternfly/components/Page/page.css"; | ||||
| // @ts-ignore | ||||
| import GlobalsStyle from "@patternfly/patternfly/base/patternfly-globals.css"; | ||||
| import { Config } from "../../api/config"; | ||||
| import { Config } from "../../api/Config"; | ||||
|  | ||||
| export const DefaultConfig: Config = { | ||||
|     branding_logo: " /static/dist/assets/icons/icon_left_brand.svg", | ||||
| @ -33,6 +33,7 @@ export class SidebarBrand extends LitElement { | ||||
|                 .pf-c-brand img { | ||||
|                     width: 100%; | ||||
|                     padding: 0 .5rem; | ||||
|                     height: 42px; | ||||
|                 } | ||||
|             `, | ||||
|         ]; | ||||
|  | ||||
							
								
								
									
										35
									
								
								web/src/elements/sidebar/SidebarHamburger.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								web/src/elements/sidebar/SidebarHamburger.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,35 @@ | ||||
| import { css, CSSResult, customElement, html, LitElement, TemplateResult } from "lit-element"; | ||||
| import { COMMON_STYLES } from "../../common/styles"; | ||||
|  | ||||
| @customElement("ak-sidebar-hamburger") | ||||
| export class SidebarHamburger extends LitElement { | ||||
|  | ||||
|     static get styles(): CSSResult[] { | ||||
|         return COMMON_STYLES.concat( | ||||
|             css` | ||||
|                 :host { | ||||
|                     position: absolute; | ||||
|                     top: var(--pf-c-page__main-section--PaddingTop); | ||||
|                     right: var(--pf-c-page__main-section--PaddingRight); | ||||
|                     z-index: 250; | ||||
|                 } | ||||
|             ` | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     onClick(): void { | ||||
|         this.dispatchEvent( | ||||
|             new CustomEvent("ak-sidebar-toggle", { | ||||
|                 bubbles: true, | ||||
|                 composed: true, | ||||
|             }) | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     render(): TemplateResult { | ||||
|         return html`<button @click=${() => (this.onClick())} class="pf-c-button pf-m-plain" type="button"> | ||||
|             <i class="fas fa-bars" aria-hidden="true"></i> | ||||
|         </button>`; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @ -5,7 +5,7 @@ import NavStyle from "@patternfly/patternfly/components/Nav/nav.css"; | ||||
| import fa from "@fortawesome/fontawesome-free/css/all.css"; | ||||
| // @ts-ignore | ||||
| import AvatarStyle from "@patternfly/patternfly/components/Avatar/avatar.css"; | ||||
| import { User } from "../../api/user"; | ||||
| import { User } from "../../api/Users"; | ||||
| import { until } from "lit-html/directives/until"; | ||||
|  | ||||
| @customElement("ak-sidebar-user") | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| import { gettext } from "django"; | ||||
| import { CSSResult, html, LitElement, property, TemplateResult } from "lit-element"; | ||||
| import { PBResponse } from "../../api/client"; | ||||
| import { PBResponse } from "../../api/Client"; | ||||
| import { COMMON_STYLES } from "../../common/styles"; | ||||
|  | ||||
| import "./TablePagination"; | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| import { CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element"; | ||||
| import { COMMON_STYLES } from "../../common/styles"; | ||||
| import { PBPagination } from "../../api/client"; | ||||
| import { PBPagination } from "../../api/Client"; | ||||
|  | ||||
| @customElement("ak-table-pagination") | ||||
| export class TablePagination extends LitElement { | ||||
|  | ||||
| @ -1,17 +1,19 @@ | ||||
| import { customElement } from "lit-element"; | ||||
| import { User } from "../api/user"; | ||||
| import { User } from "../api/Users"; | ||||
| import { SidebarItem } from "../elements/sidebar/Sidebar"; | ||||
| import { SLUG_REGEX } from "../elements/router/Route"; | ||||
| import { Interface } from "./Interface"; | ||||
|  | ||||
| export const SIDEBAR_ITEMS: SidebarItem[] = [ | ||||
|     new SidebarItem("Library", "/library/"), | ||||
|     new SidebarItem("Monitor", "/audit/audit").when((): Promise<boolean> => { | ||||
|     new SidebarItem("Monitor").children( | ||||
|         new SidebarItem("Overview", "/administration/overview/"), | ||||
|         new SidebarItem("System Tasks", "/administration/tasks/"), | ||||
|         new SidebarItem("Events", "/audit/audit"), | ||||
|     ).when((): Promise<boolean> => { | ||||
|         return User.me().then(u => u.is_superuser); | ||||
|     }), | ||||
|     new SidebarItem("Administration").children( | ||||
|         new SidebarItem("Overview", "/administration/overview-ng/"), | ||||
|         new SidebarItem("System Tasks", "/administration/tasks/"), | ||||
|         new SidebarItem("Applications", "/administration/applications/").activeWhen( | ||||
|             `^/applications/(?<slug>${SLUG_REGEX})/$` | ||||
|         ), | ||||
| @ -19,27 +21,29 @@ export const SIDEBAR_ITEMS: SidebarItem[] = [ | ||||
|             `^/sources/(?<slug>${SLUG_REGEX})/$`, | ||||
|         ), | ||||
|         new SidebarItem("Providers", "/administration/providers/"), | ||||
|         new SidebarItem("Flows").children( | ||||
|             new SidebarItem("Flows", "/administration/flows/").activeWhen(`^/flows/(?<slug>${SLUG_REGEX})/$`), | ||||
|             new SidebarItem("Stages", "/administration/stages/"), | ||||
|             new SidebarItem("Prompts", "/administration/stages/prompts/"), | ||||
|             new SidebarItem("Invitations", "/administration/stages/invitations/"), | ||||
|         ), | ||||
|         new SidebarItem("User Management").children( | ||||
|             new SidebarItem("User", "/administration/users/"), | ||||
|             new SidebarItem("Groups", "/administration/groups/") | ||||
|         ), | ||||
|         new SidebarItem("Outposts").children( | ||||
|             new SidebarItem("Outposts", "/administration/outposts/"), | ||||
|             new SidebarItem("Service Connections", "/administration/outposts/service_connections/") | ||||
|         ), | ||||
|         new SidebarItem("Outposts", "/administration/outposts/"), | ||||
|         new SidebarItem("Outpost Service Connections", "/administration/outposts/service_connections/"), | ||||
|         new SidebarItem("Policies", "/administration/policies/"), | ||||
|         new SidebarItem("Property Mappings", "/administration/property-mappings"), | ||||
|         new SidebarItem("Certificates", "/administration/crypto/certificates"), | ||||
|         new SidebarItem("Tokens", "/administration/tokens/"), | ||||
|     ).when((): Promise<boolean> => { | ||||
|         return User.me().then(u => u.is_superuser); | ||||
|     }) | ||||
|     }), | ||||
|     new SidebarItem("Flows").children( | ||||
|         new SidebarItem("Flows", "/administration/flows/").activeWhen(`^/flows/(?<slug>${SLUG_REGEX})/$`), | ||||
|         new SidebarItem("Stages", "/administration/stages/"), | ||||
|         new SidebarItem("Prompts", "/administration/stages/prompts/"), | ||||
|         new SidebarItem("Invitations", "/administration/stages/invitations/"), | ||||
|     ).when((): Promise<boolean> => { | ||||
|         return User.me().then(u => u.is_superuser); | ||||
|     }), | ||||
|     new SidebarItem("User Management").children( | ||||
|         new SidebarItem("User", "/administration/users/"), | ||||
|         new SidebarItem("Groups", "/administration/groups/") | ||||
|     ).when((): Promise<boolean> => { | ||||
|         return User.me().then(u => u.is_superuser); | ||||
|     }), | ||||
| ]; | ||||
|  | ||||
| @customElement("ak-interface-admin") | ||||
|  | ||||
| @ -1,11 +1,14 @@ | ||||
| import { gettext } from "django"; | ||||
| import { html, LitElement, TemplateResult } from "lit-element"; | ||||
| import { html, LitElement, property, TemplateResult } from "lit-element"; | ||||
| import { SidebarItem } from "../elements/sidebar/Sidebar"; | ||||
|  | ||||
| import "../elements/router/RouterOutlet"; | ||||
| import "../elements/messages/MessageContainer"; | ||||
| import "../elements/sidebar/SidebarHamburger"; | ||||
|  | ||||
| export abstract class Interface extends LitElement { | ||||
|     @property({type: Boolean}) | ||||
|     sidebarOpen?: boolean; | ||||
|  | ||||
|     abstract get sidebar(): SidebarItem[]; | ||||
|  | ||||
| @ -13,11 +16,20 @@ export abstract class Interface extends LitElement { | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     constructor() { | ||||
|         super(); | ||||
|         window.addEventListener("ak-sidebar-toggle", () => { | ||||
|             this.sidebarOpen = !this.sidebarOpen; | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     render(): TemplateResult { | ||||
|         return html`<ak-message-container></ak-message-container> | ||||
|             <div class="pf-c-page"> | ||||
|                 <a class="pf-c-skip-to-content pf-c-button pf-m-primary" href="#main-content">${gettext("Skip to content")}</a> | ||||
|                 <ak-sidebar class="pf-c-page__sidebar" .items=${this.sidebar}> | ||||
|                 <ak-sidebar-hamburger> | ||||
|                 </ak-sidebar-hamburger> | ||||
|                 <ak-sidebar class="pf-c-page__sidebar ${this.sidebarOpen ? "pf-m-expanded" : "pf-m-collapsed"}" .items=${this.sidebar}> | ||||
|                 </ak-sidebar> | ||||
|                 <main class="pf-c-page__main"> | ||||
|                     <ak-router-outlet role="main" class="pf-c-page__main" tabindex="-1" id="main-content" defaultUrl="/library/"> | ||||
|  | ||||
| @ -1,8 +1,8 @@ | ||||
| import { gettext } from "django"; | ||||
| import { css, CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element"; | ||||
| import { ifDefined } from "lit-html/directives/if-defined"; | ||||
| import { Application } from "../api/application"; | ||||
| import { PBResponse } from "../api/client"; | ||||
| import { Application } from "../api/Applications"; | ||||
| import { PBResponse } from "../api/Client"; | ||||
| import { COMMON_STYLES } from "../common/styles"; | ||||
| import { loading, truncate } from "../utils"; | ||||
|  | ||||
|  | ||||
| @ -1,71 +1,27 @@ | ||||
| import { gettext } from "django"; | ||||
| import { CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element"; | ||||
| import { AdminOverview } from "../../api/admin_overview"; | ||||
| import { DefaultClient } from "../../api/client"; | ||||
| import { User } from "../../api/user"; | ||||
| import { CSSResult, customElement, html, LitElement, TemplateResult } from "lit-element"; | ||||
| import { DefaultClient } from "../../api/Client"; | ||||
| import { COMMON_STYLES } from "../../common/styles"; | ||||
| import { AggregatePromiseCard } from "../../elements/cards/AggregatePromiseCard"; | ||||
| import { SpinnerSize } from "../../elements/Spinner"; | ||||
|  | ||||
| import "../../elements/AdminLoginsChart"; | ||||
| import "../../elements/cards/AggregatePromiseCard"; | ||||
| import "./TopApplicationsTable"; | ||||
|  | ||||
| @customElement("ak-admin-status-card") | ||||
| export class AdminStatusCard extends AggregatePromiseCard { | ||||
|  | ||||
|     @property({type: Number}) | ||||
|     value?: number; | ||||
|  | ||||
|     @property() | ||||
|     warningText?: string; | ||||
|  | ||||
|     @property({type: Number}) | ||||
|     lessThanThreshold?: number; | ||||
|  | ||||
|     renderNone(): TemplateResult { | ||||
|         return html`<ak-spinner size=${SpinnerSize.Large}></ak-spinner>`; | ||||
|     } | ||||
|  | ||||
|     renderGood(): TemplateResult { | ||||
|         return html`<p class="ak-aggregate-card"> | ||||
|             <i class="fa fa-check-circle"></i> ${this.value} | ||||
|         </p>`; | ||||
|     } | ||||
|  | ||||
|     renderBad(): TemplateResult { | ||||
|         return html`<p class="ak-aggregate-card"> | ||||
|             <i class="fa fa-exclamation-triangle"></i> ${this.value} | ||||
|         </p> | ||||
|         <p class="subtext">${this.warningText ? gettext(this.warningText) : ""}</p>`; | ||||
|     } | ||||
|  | ||||
|     renderInner(): TemplateResult { | ||||
|         if (!this.value) { | ||||
|             return this.renderNone(); | ||||
|         } | ||||
|  | ||||
|         return html``; | ||||
|     } | ||||
|  | ||||
| } | ||||
| import "./cards/AdminStatusCard"; | ||||
| import "./cards/FlowCacheStatusCard"; | ||||
| import "./cards/PolicyCacheStatusCard"; | ||||
| import "./cards/PolicyUnboundStatusCard"; | ||||
| import "./cards/ProviderStatusCard"; | ||||
| import "./cards/UserCountStatusCard"; | ||||
| import "./cards/VersionStatusCard"; | ||||
| import "./cards/WorkerStatusCard"; | ||||
|  | ||||
| @customElement("ak-admin-overview") | ||||
| export class AdminOverviewPage extends LitElement { | ||||
|     @property({attribute: false}) | ||||
|     data?: AdminOverview; | ||||
|  | ||||
|     @property({attribute: false}) | ||||
|     users?: Promise<number>; | ||||
|  | ||||
|     static get styles(): CSSResult[] { | ||||
|         return COMMON_STYLES; | ||||
|     } | ||||
|  | ||||
|     firstUpdated(): void { | ||||
|         AdminOverview.get().then(value => this.data = value); | ||||
|         this.users = User.count(); | ||||
|     } | ||||
|  | ||||
|     render(): TemplateResult { | ||||
|         return html`<section class="pf-c-page__main-section pf-m-light"> | ||||
|             <div class="pf-c-content"> | ||||
| @ -80,48 +36,20 @@ export class AdminOverviewPage extends LitElement { | ||||
|                 <ak-aggregate-card class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-server" header="Apps with most usage" style="grid-column-end: span 2;grid-row-end: span 3;"> | ||||
|                     <ak-top-applications-table></ak-top-applications-table> | ||||
|                 </ak-aggregate-card> | ||||
|                 <ak-aggregate-card class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-server" header="Workers"> | ||||
|                     ${this.data ? | ||||
|         this.data?.worker_count < 1 ? | ||||
|             html`<p class="ak-aggregate-card"> | ||||
|                                     <i class="fa fa-exclamation-triangle"></i> ${this.data?.worker_count} | ||||
|                                 </p> | ||||
|                                 <p class="subtext">${gettext("No workers connected.")}</p>` : | ||||
|             html`<p class="ak-aggregate-card"> | ||||
|                                     <i class="fa fa-check-circle"></i> ${this.data?.worker_count} | ||||
|                                 </p>` | ||||
|         : html`<ak-spinner size=${SpinnerSize.Large}></ak-spinner>`} | ||||
|                 </ak-aggregate-card> | ||||
|                 <ak-aggregate-card class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-plugged" header="Providers" headerLink="#/administration/providers/"> | ||||
|                     ${this.data ? | ||||
|         this.data?.providers_without_application > 1 ? | ||||
|             html`<p class="ak-aggregate-card"> | ||||
|                                     <i class="fa fa-exclamation-triangle"></i> 0 | ||||
|                                 </p> | ||||
|                                 <p class="subtext">${gettext("At least one Provider has no application assigned.")}</p>` : | ||||
|             html`<p class="ak-aggregate-card"> | ||||
|                                     <i class="fa fa-check-circle"></i> 0 | ||||
|                                 </p>` | ||||
|         : html`<ak-spinner size=${SpinnerSize.Large}></ak-spinner>`} | ||||
|                 </ak-aggregate-card> | ||||
|                 <ak-aggregate-card class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-plugged" header="Policies" headerLink="#/administration/policies/"> | ||||
|                     ${this.data ? | ||||
|         this.data?.policies_without_binding > 1 ? | ||||
|             html`<p class="ak-aggregate-card"> | ||||
|                                     <i class="fa fa-exclamation-triangle"></i> 0 | ||||
|                                 </p> | ||||
|                                 <p class="subtext">${gettext("Policies without binding exist.")}</p>` : | ||||
|             html`<p class="ak-aggregate-card"> | ||||
|                                     <i class="fa fa-check-circle"></i> 0 | ||||
|                                 </p>` | ||||
|         : html`<ak-spinner size=${SpinnerSize.Large}></ak-spinner>`} | ||||
|                 </ak-aggregate-card> | ||||
|                 <ak-aggregate-card-promise | ||||
|                     icon="pf-icon pf-icon-user" | ||||
|                     header="Users" | ||||
|                     headerLink="#/administration/users/" | ||||
|                     .promise=${this.users}> | ||||
|                 </ak-aggregate-card-promise> | ||||
|                 <ak-admin-status-card-provider class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-plugged" header="Providers" headerLink="#/administration/providers/"> | ||||
|                 </ak-admin-status-card-provider> | ||||
|                 <ak-admin-status-card-policy-unbound class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-infrastructure" header="Policies" headerLink="#/administration/policies/"> | ||||
|                 </ak-admin-status-card-policy-unbound> | ||||
|                 <ak-admin-status-card-user-count class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-user" header="Users" headerLink="#/administration/users/"> | ||||
|                 </ak-admin-status-card-user-count> | ||||
|                 <ak-admin-status-version class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-bundle" header="Version" headerLink="https://github.com/BeryJu/authentik/releases"> | ||||
|                 </ak-admin-status-version> | ||||
|                 <ak-admin-status-card-workers class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-server" header="Workers"> | ||||
|                 </ak-admin-status-card-workers> | ||||
|                 <ak-admin-status-card-policy-cache class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-server" header="Cached Policies"> | ||||
|                 </ak-admin-status-card-policy-cache> | ||||
|                 <ak-admin-status-card-flow-cache class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-server" header="Cached Flows"> | ||||
|                 </ak-admin-status-card-flow-cache> | ||||
|             </div> | ||||
|         </section>`; | ||||
|     } | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| import { gettext } from "django"; | ||||
| import { CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element"; | ||||
| import { AuditEvent, TopNEvent } from "../../api/events"; | ||||
| import { AuditEvent, TopNEvent } from "../../api/Events"; | ||||
| import { COMMON_STYLES } from "../../common/styles"; | ||||
|  | ||||
| import "../../elements/Spinner"; | ||||
|  | ||||
							
								
								
									
										37
									
								
								web/src/pages/admin-overview/cards/AdminStatusCard.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								web/src/pages/admin-overview/cards/AdminStatusCard.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,37 @@ | ||||
| import { html, TemplateResult } from "lit-html"; | ||||
| import { until } from "lit-html/directives/until"; | ||||
| import { AggregateCard } from "../../../elements/cards/AggregateCard"; | ||||
| import { SpinnerSize } from "../../../elements/Spinner"; | ||||
|  | ||||
| export interface AdminStatus { | ||||
|     icon: string; | ||||
|     message?: string; | ||||
| } | ||||
|  | ||||
| export abstract class AdminStatusCard<T> extends AggregateCard { | ||||
|  | ||||
|     abstract getPrimaryValue(): Promise<T>; | ||||
|  | ||||
|     abstract getStatus(value: T): Promise<AdminStatus>; | ||||
|  | ||||
|     value?: T; | ||||
|  | ||||
|     renderValue(): TemplateResult { | ||||
|         return html`${this.value}`; | ||||
|     } | ||||
|  | ||||
|     renderInner(): TemplateResult { | ||||
|         return html`<p class="center-value"> | ||||
|             ${until(this.getPrimaryValue().then((v) => { | ||||
|         this.value = v; | ||||
|         return this.getStatus(v); | ||||
|     }).then((status) => { | ||||
|         return html`<p class="ak-aggregate-card"> | ||||
|                     <i class="${status.icon}"></i> ${this.renderValue()} | ||||
|                 </p> | ||||
|                 ${status.message ? html`<p class="subtext">${status.message}</p>` : html``}`; | ||||
|     }), html`<ak-spinner size="${SpinnerSize.Large}"></ak-spinner>`)} | ||||
|         </p>`; | ||||
|     } | ||||
| } | ||||
|  | ||||
							
								
								
									
										36
									
								
								web/src/pages/admin-overview/cards/FlowCacheStatusCard.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								web/src/pages/admin-overview/cards/FlowCacheStatusCard.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,36 @@ | ||||
| import { gettext } from "django"; | ||||
| import { customElement, html, TemplateResult } from "lit-element"; | ||||
| import { Flow } from "../../../api/Flows"; | ||||
| import { AdminStatus, AdminStatusCard } from "./AdminStatusCard"; | ||||
| import "../../../elements/buttons/ModalButton"; | ||||
|  | ||||
| @customElement("ak-admin-status-card-flow-cache") | ||||
| export class FlowCacheStatusCard extends AdminStatusCard<number> { | ||||
|  | ||||
|     getPrimaryValue(): Promise<number> { | ||||
|         return Flow.cached(); | ||||
|     } | ||||
|  | ||||
|     getStatus(value: number): Promise<AdminStatus> { | ||||
|         if (value < 1) { | ||||
|             return Promise.resolve<AdminStatus>({ | ||||
|                 icon: "fa fa-exclamation-triangle pf-m-warning", | ||||
|                 message: gettext("No flows cached."), | ||||
|             }); | ||||
|         } else { | ||||
|             return Promise.resolve<AdminStatus>({ | ||||
|                 icon: "fa fa-check-circle pf-m-success" | ||||
|             }); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     renderHeaderLink(): TemplateResult { | ||||
|         return html`<ak-modal-button href="/administration/overview/cache/flow/"> | ||||
|             <a slot="trigger"> | ||||
|                 <i class="fa fa-trash"> </i> | ||||
|             </a> | ||||
|             <div slot="modal"></div> | ||||
|         </ak-modal-button>`; | ||||
|     } | ||||
|  | ||||
| } | ||||
							
								
								
									
										37
									
								
								web/src/pages/admin-overview/cards/PolicyCacheStatusCard.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								web/src/pages/admin-overview/cards/PolicyCacheStatusCard.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,37 @@ | ||||
| import { gettext } from "django"; | ||||
| import { customElement } from "lit-element"; | ||||
| import { TemplateResult, html } from "lit-html"; | ||||
| import { Policy } from "../../../api/Policies"; | ||||
| import { AdminStatusCard, AdminStatus } from "./AdminStatusCard"; | ||||
| import "../../../elements/buttons/ModalButton"; | ||||
|  | ||||
| @customElement("ak-admin-status-card-policy-cache") | ||||
| export class PolicyCacheStatusCard extends AdminStatusCard<number> { | ||||
|  | ||||
|     getPrimaryValue(): Promise<number> { | ||||
|         return Policy.cached(); | ||||
|     } | ||||
|  | ||||
|     getStatus(value: number): Promise<AdminStatus> { | ||||
|         if (value < 1) { | ||||
|             return Promise.resolve<AdminStatus>({ | ||||
|                 icon: "fa fa-exclamation-triangle pf-m-warning", | ||||
|                 message: gettext("No policies cached. Users may experience slow response times."), | ||||
|             }); | ||||
|         } else { | ||||
|             return Promise.resolve<AdminStatus>({ | ||||
|                 icon: "fa fa-check-circle pf-m-success" | ||||
|             }); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     renderHeaderLink(): TemplateResult { | ||||
|         return html`<ak-modal-button href="/administration/overview/cache/policy/"> | ||||
|             <a slot="trigger"> | ||||
|                 <i class="fa fa-trash"> </i> | ||||
|             </a> | ||||
|             <div slot="modal"></div> | ||||
|         </ak-modal-button>`; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @ -0,0 +1,31 @@ | ||||
| import { gettext } from "django"; | ||||
| import { customElement } from "lit-element"; | ||||
| import { Policy } from "../../../api/Policies"; | ||||
| import { AdminStatusCard, AdminStatus } from "./AdminStatusCard"; | ||||
|  | ||||
| @customElement("ak-admin-status-card-policy-unbound") | ||||
| export class PolicyUnboundStatusCard extends AdminStatusCard<number> { | ||||
|  | ||||
|     getPrimaryValue(): Promise<number> { | ||||
|         return Policy.list({ | ||||
|             "bindings__isnull": true, | ||||
|             "promptstage__isnull": true, | ||||
|         }).then((response) => { | ||||
|             return response.pagination.count; | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     getStatus(value: number): Promise<AdminStatus> { | ||||
|         if (value > 0) { | ||||
|             return Promise.resolve<AdminStatus>({ | ||||
|                 icon: "fa fa-exclamation-triangle pf-m-warning", | ||||
|                 message: gettext("Policies without binding exist."), | ||||
|             }); | ||||
|         } else { | ||||
|             return Promise.resolve<AdminStatus>({ | ||||
|                 icon: "fa fa-check-circle pf-m-success" | ||||
|             }); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
							
								
								
									
										30
									
								
								web/src/pages/admin-overview/cards/ProviderStatusCard.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								web/src/pages/admin-overview/cards/ProviderStatusCard.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,30 @@ | ||||
| import { gettext } from "django"; | ||||
| import { customElement } from "lit-element"; | ||||
| import { Provider } from "../../../api/Providers"; | ||||
| import { AdminStatusCard, AdminStatus } from "./AdminStatusCard"; | ||||
|  | ||||
| @customElement("ak-admin-status-card-provider") | ||||
| export class ProviderStatusCard extends AdminStatusCard<number> { | ||||
|  | ||||
|     getPrimaryValue(): Promise<number> { | ||||
|         return Provider.list({ | ||||
|             "application__isnull": true | ||||
|         }).then((response) => { | ||||
|             return response.pagination.count; | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     getStatus(value: number): Promise<AdminStatus> { | ||||
|         if (value > 0) { | ||||
|             return Promise.resolve<AdminStatus>({ | ||||
|                 icon: "fa fa-exclamation-triangle pf-m-warning", | ||||
|                 message: gettext("Warning: At least one Provider has no application assigned."), | ||||
|             }); | ||||
|         } else { | ||||
|             return Promise.resolve<AdminStatus>({ | ||||
|                 icon: "fa fa-check-circle pf-m-success" | ||||
|             }); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
							
								
								
									
										19
									
								
								web/src/pages/admin-overview/cards/UserCountStatusCard.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								web/src/pages/admin-overview/cards/UserCountStatusCard.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | ||||
| import { customElement } from "lit-element"; | ||||
| import { User } from "../../../api/Users"; | ||||
| import { AdminStatusCard, AdminStatus } from "./AdminStatusCard"; | ||||
|  | ||||
| @customElement("ak-admin-status-card-user-count") | ||||
| export class UserCountStatusCard extends AdminStatusCard<number> { | ||||
|  | ||||
|     getPrimaryValue(): Promise<number> { | ||||
|         return User.count(); | ||||
|     } | ||||
|  | ||||
|     // eslint-disable-next-line @typescript-eslint/no-unused-vars | ||||
|     getStatus(value: number): Promise<AdminStatus> { | ||||
|         return Promise.resolve<AdminStatus>({ | ||||
|             icon: "fa fa-check-circle pf-m-success" | ||||
|         }); | ||||
|     } | ||||
|  | ||||
| } | ||||
							
								
								
									
										31
									
								
								web/src/pages/admin-overview/cards/VersionStatusCard.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								web/src/pages/admin-overview/cards/VersionStatusCard.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,31 @@ | ||||
| import { gettext } from "django"; | ||||
| import { customElement, html, TemplateResult } from "lit-element"; | ||||
| import { Version } from "../../../api/Versions"; | ||||
| import { AdminStatusCard, AdminStatus } from "./AdminStatusCard"; | ||||
|  | ||||
| @customElement("ak-admin-status-version") | ||||
| export class VersionStatusCard extends AdminStatusCard<Version> { | ||||
|  | ||||
|     getPrimaryValue(): Promise<Version> { | ||||
|         return Version.get(); | ||||
|     } | ||||
|  | ||||
|     getStatus(value: Version): Promise<AdminStatus> { | ||||
|         if (value.outdated) { | ||||
|             return Promise.resolve<AdminStatus>({ | ||||
|                 icon: "fa fa-exclamation-triangle pf-m-warning", | ||||
|                 message: gettext(`${value.version_latest} is available!`), | ||||
|             }); | ||||
|         } else { | ||||
|             return Promise.resolve<AdminStatus>({ | ||||
|                 icon: "fa fa-check-circle pf-m-success", | ||||
|                 message: gettext("Up-to-date!") | ||||
|             }); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     renderValue(): TemplateResult { | ||||
|         return html`${this.value?.version_current}`; | ||||
|     } | ||||
|  | ||||
| } | ||||
							
								
								
									
										28
									
								
								web/src/pages/admin-overview/cards/WorkerStatusCard.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								web/src/pages/admin-overview/cards/WorkerStatusCard.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | ||||
| import { gettext } from "django"; | ||||
| import { customElement } from "lit-element"; | ||||
| import { DefaultClient, PBResponse } from "../../../api/Client"; | ||||
| import { AdminStatus, AdminStatusCard } from "./AdminStatusCard"; | ||||
|  | ||||
| @customElement("ak-admin-status-card-workers") | ||||
| export class WorkersStatusCard extends AdminStatusCard<number> { | ||||
|  | ||||
|     getPrimaryValue(): Promise<number> { | ||||
|         return DefaultClient.fetch<PBResponse<number>>(["admin", "workers"]).then((r) => { | ||||
|             return r.pagination.count; | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     getStatus(value: number): Promise<AdminStatus> { | ||||
|         if (value < 1) { | ||||
|             return Promise.resolve<AdminStatus>({ | ||||
|                 icon: "fa fa-exclamation-triangle pf-m-warning", | ||||
|                 message: gettext("No workers connected. Background tasks will not run."), | ||||
|             }); | ||||
|         } else { | ||||
|             return Promise.resolve<AdminStatus>({ | ||||
|                 icon: "fa fa-check-circle pf-m-success" | ||||
|             }); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
| @ -1,7 +1,7 @@ | ||||
| import { gettext } from "django"; | ||||
| import { customElement, html, TemplateResult } from "lit-element"; | ||||
| import { Application } from "../../api/application"; | ||||
| import { PBResponse } from "../../api/client"; | ||||
| import { Application } from "../../api/Applications"; | ||||
| import { PBResponse } from "../../api/Client"; | ||||
| import { TablePage } from "../../elements/table/TablePage"; | ||||
|  | ||||
| import "../../elements/buttons/ModalButton"; | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| import { gettext } from "django"; | ||||
| import { css, CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element"; | ||||
| import { Application } from "../../api/application"; | ||||
| import { DefaultClient } from "../../api/client"; | ||||
| import { Application } from "../../api/Applications"; | ||||
| import { DefaultClient } from "../../api/Client"; | ||||
| import { COMMON_STYLES } from "../../common/styles"; | ||||
|  | ||||
| import "../../elements/Tabs"; | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| import { gettext } from "django"; | ||||
| import { customElement, html, property, TemplateResult } from "lit-element"; | ||||
| import { PBResponse } from "../../api/client"; | ||||
| import { PBResponse } from "../../api/Client"; | ||||
| import { Table } from "../../elements/table/Table"; | ||||
|  | ||||
| import "../../elements/Tabs"; | ||||
| @ -8,7 +8,7 @@ import "../../elements/AdminLoginsChart"; | ||||
| import "../../elements/buttons/ModalButton"; | ||||
| import "../../elements/buttons/SpinnerButton"; | ||||
| import "../../elements/policies/BoundPoliciesList"; | ||||
| import { FlowStageBinding } from "../../api/flow"; | ||||
| import { FlowStageBinding } from "../../api/Flows"; | ||||
|  | ||||
| @customElement("ak-bound-stages-list") | ||||
| export class BoundStagesList extends Table<FlowStageBinding> { | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| import { gettext } from "django"; | ||||
| import { css, CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element"; | ||||
| import { COMMON_STYLES } from "../../common/styles"; | ||||
| import { Flow } from "../../api/flow"; | ||||
| import { Flow } from "../../api/Flows"; | ||||
|  | ||||
| import "../../elements/Tabs"; | ||||
| import "../../elements/AdminLoginsChart"; | ||||
|  | ||||
| @ -7,7 +7,7 @@ import "../../elements/AdminLoginsChart"; | ||||
| import "../../elements/buttons/ModalButton"; | ||||
| import "../../elements/buttons/SpinnerButton"; | ||||
| import "../../elements/policies/BoundPoliciesList"; | ||||
| import { Source } from "../../api/source"; | ||||
| import { Source } from "../../api/Sources"; | ||||
|  | ||||
| @customElement("ak-source-view") | ||||
| export class SourceViewPage extends LitElement { | ||||
|  | ||||
| @ -13,7 +13,7 @@ export const ROUTES: Route[] = [ | ||||
|     new Route(new RegExp("^/$")).redirect("/library/"), | ||||
|     new Route(new RegExp("^#.*")).redirect("/library/"), | ||||
|     new Route(new RegExp("^/library/$"), html`<ak-library></ak-library>`), | ||||
|     new Route(new RegExp("^/administration/overview-ng/$"), html`<ak-admin-overview></ak-admin-overview>`), | ||||
|     new Route(new RegExp("^/administration/overview/$"), html`<ak-admin-overview></ak-admin-overview>`), | ||||
|     new Route(new RegExp("^/applications/$"), html`<ak-application-list></ak-application-list>`), | ||||
|     new Route(new RegExp(`^/applications/(?<slug>${SLUG_REGEX})/$`)).then((args) => { | ||||
|         return html`<ak-application-view .args=${args}></ak-application-view>`; | ||||
|  | ||||
| @ -15,7 +15,7 @@ Download the latest `docker-compose.yml` from [here](https://raw.githubuserconte | ||||
|  | ||||
| To optionally enable error-reporting, run `echo AUTHENTIK_ERROR_REPORTING__ENABLED=true >> .env` | ||||
|  | ||||
| To optionally deploy a different version run `echo AUTHENTIK_TAG=0.13.0-rc4 >> .env` | ||||
| To optionally deploy a different version run `echo AUTHENTIK_TAG=0.13.3-stable >> .env` | ||||
|  | ||||
| If this is a fresh authentik install run the following commands to generate a password: | ||||
|  | ||||
|  | ||||
| @ -22,7 +22,7 @@ image: | ||||
|     name: beryju/authentik | ||||
|     name_static: beryju/authentik-static | ||||
|     name_outposts: beryju/authentik # Prefix used for Outpost deployments, Outpost type and version is appended | ||||
|     tag: 0.13.0-rc4 | ||||
|     tag: 0.13.3-stable | ||||
|  | ||||
| serverReplicas: 1 | ||||
| workerReplicas: 1 | ||||
|  | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user
	