fix: merge master (#1306)

* chore(site): dependabot deps (#1148)

* chore(deps): bump highlight.js from 10.4.1 to 10.5.0 in /site (#1143)

Bumps [highlight.js](https://github.com/highlightjs/highlight.js) from 10.4.1 to 10.5.0.
- [Release notes](https://github.com/highlightjs/highlight.js/releases)
- [Changelog](https://github.com/highlightjs/highlight.js/blob/master/CHANGES.md)
- [Commits](https://github.com/highlightjs/highlight.js/compare/10.4.1...10.5.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump @babel/plugin-transform-runtime in /site (#1144)

Bumps [@babel/plugin-transform-runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-plugin-transform-runtime) from 7.12.1 to 7.12.10.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.12.10/packages/babel-plugin-transform-runtime)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps): bump sirv from 1.0.7 to 1.0.10 in /site (#1145)

Bumps [sirv](https://github.com/lukeed/sirv) from 1.0.7 to 1.0.10.
- [Release notes](https://github.com/lukeed/sirv/releases)
- [Commits](https://github.com/lukeed/sirv/compare/v1.0.7...v1.0.10)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump rollup from 2.34.0 to 2.35.1 in /site (#1142)

Bumps [rollup](https://github.com/rollup/rollup) from 2.34.0 to 2.35.1.
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v2.34.0...v2.35.1)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump @rollup/plugin-node-resolve in /site (#1141)

Bumps [@rollup/plugin-node-resolve](https://github.com/rollup/plugins) from 10.0.0 to 11.0.1.
- [Release notes](https://github.com/rollup/plugins/releases)
- [Commits](https://github.com/rollup/plugins/compare/node-resolve-v10.0.0...commonjs-v11.0.1)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps): bump marked from 1.2.5 to 1.2.7 in /site (#1140)

Bumps [marked](https://github.com/markedjs/marked) from 1.2.5 to 1.2.7.
- [Release notes](https://github.com/markedjs/marked/releases)
- [Changelog](https://github.com/markedjs/marked/blob/master/release.config.js)
- [Commits](https://github.com/markedjs/marked/compare/v1.2.5...v1.2.7)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump @babel/core from 7.12.9 to 7.12.10 in /site (#1139)

Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.12.9 to 7.12.10.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.12.10/packages/babel-core)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump rollup-plugin-svelte from 6.1.1 to 7.0.0 in /site (#1138)

Bumps [rollup-plugin-svelte](https://github.com/sveltejs/rollup-plugin-svelte) from 6.1.1 to 7.0.0.
- [Release notes](https://github.com/sveltejs/rollup-plugin-svelte/releases)
- [Changelog](https://github.com/sveltejs/rollup-plugin-svelte/blob/master/CHANGELOG.md)
- [Commits](https://github.com/sveltejs/rollup-plugin-svelte/compare/v6.1.1...v7.0.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump @babel/preset-env from 7.12.1 to 7.12.11 in /site (#1137)

Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.12.1 to 7.12.11.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.12.11/packages/babel-preset-env)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* downgrade svelte plugin

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(console): dependabot deps (#1147)

* chore(deps-dev): bump @types/node from 14.14.13 to 14.14.19 in /console (#1146)

Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 14.14.13 to 14.14.19.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps): bump ts-protoc-gen from 0.13.0 to 0.14.0 in /console (#1129)

Bumps [ts-protoc-gen](https://github.com/improbable-eng/ts-protoc-gen) from 0.13.0 to 0.14.0.
- [Release notes](https://github.com/improbable-eng/ts-protoc-gen/releases)
- [Changelog](https://github.com/improbable-eng/ts-protoc-gen/blob/master/CHANGELOG.md)
- [Commits](https://github.com/improbable-eng/ts-protoc-gen/compare/0.13.0...0.14.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump @angular/language-service in /console (#1128)

Bumps [@angular/language-service](https://github.com/angular/angular/tree/HEAD/packages/language-service) from 11.0.4 to 11.0.5.
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/master/CHANGELOG.md)
- [Commits](https://github.com/angular/angular/commits/11.0.5/packages/language-service)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump @angular/cli from 11.0.4 to 11.0.5 in /console (#1127)

Bumps [@angular/cli](https://github.com/angular/angular-cli) from 11.0.4 to 11.0.5.
- [Release notes](https://github.com/angular/angular-cli/releases)
- [Commits](https://github.com/angular/angular-cli/compare/v11.0.4...v11.0.5)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump @angular-devkit/build-angular in /console (#1126)

Bumps [@angular-devkit/build-angular](https://github.com/angular/angular-cli) from 0.1100.4 to 0.1100.5.
- [Release notes](https://github.com/angular/angular-cli/releases)
- [Commits](https://github.com/angular/angular-cli/commits)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Max Peintner <max@caos.ch>

* audit

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* feat: e-mail templates (#1158)

* View definition added

* Get templates and texts from the database.

* Fill in texts in templates

* Fill in texts in templates

* Client API added

* Weekly backup

* Weekly backup

* Daily backup

* Weekly backup

* Tests added

* Corrections from merge branch

* Fixes from pull request review

* chore(console): dependencies (#1189)

* chore(deps-dev): bump @angular/language-service in /console (#1187)

Bumps [@angular/language-service](https://github.com/angular/angular/tree/HEAD/packages/language-service) from 11.0.5 to 11.0.9.
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/master/CHANGELOG.md)
- [Commits](https://github.com/angular/angular/commits/11.0.9/packages/language-service)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps): bump google-proto-files from 2.3.0 to 2.4.0 in /console (#1186)

Bumps [google-proto-files](https://github.com/googleapis/nodejs-proto-files) from 2.3.0 to 2.4.0.
- [Release notes](https://github.com/googleapis/nodejs-proto-files/releases)
- [Changelog](https://github.com/googleapis/nodejs-proto-files/blob/master/CHANGELOG.md)
- [Commits](https://github.com/googleapis/nodejs-proto-files/compare/v2.3.0...v2.4.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump @types/node from 14.14.19 to 14.14.21 in /console (#1185)

Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 14.14.19 to 14.14.21.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump @angular/cli from 11.0.5 to 11.0.7 in /console (#1184)

Bumps [@angular/cli](https://github.com/angular/angular-cli) from 11.0.5 to 11.0.7.
- [Release notes](https://github.com/angular/angular-cli/releases)
- [Commits](https://github.com/angular/angular-cli/compare/v11.0.5...v11.0.7)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump karma from 5.2.3 to 6.0.0 in /console (#1183)

Bumps [karma](https://github.com/karma-runner/karma) from 5.2.3 to 6.0.0.
- [Release notes](https://github.com/karma-runner/karma/releases)
- [Changelog](https://github.com/karma-runner/karma/blob/master/CHANGELOG.md)
- [Commits](https://github.com/karma-runner/karma/compare/v5.2.3...v6.0.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump @angular-devkit/build-angular in /console (#1182)

Bumps [@angular-devkit/build-angular](https://github.com/angular/angular-cli) from 0.1100.5 to 0.1100.7.
- [Release notes](https://github.com/angular/angular-cli/releases)
- [Commits](https://github.com/angular/angular-cli/commits)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Max Peintner <max@caos.ch>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* fix(console): trigger unauthenticated dialog only once (#1170)

* fix: trigger dialog once

* remove log

* typed trigger

* chore(console): dependencies (#1205)

* chore(deps-dev): bump stylelint from 13.8.0 to 13.9.0 in /console (#1204)

Bumps [stylelint](https://github.com/stylelint/stylelint) from 13.8.0 to 13.9.0.
- [Release notes](https://github.com/stylelint/stylelint/releases)
- [Changelog](https://github.com/stylelint/stylelint/blob/master/CHANGELOG.md)
- [Commits](https://github.com/stylelint/stylelint/compare/13.8.0...13.9.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump @angular/language-service in /console (#1203)

Bumps [@angular/language-service](https://github.com/angular/angular/tree/HEAD/packages/language-service) from 11.0.9 to 11.1.0.
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/master/CHANGELOG.md)
- [Commits](https://github.com/angular/angular/commits/11.1.0/packages/language-service)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump karma from 6.0.0 to 6.0.1 in /console (#1202)

Bumps [karma](https://github.com/karma-runner/karma) from 6.0.0 to 6.0.1.
- [Release notes](https://github.com/karma-runner/karma/releases)
- [Changelog](https://github.com/karma-runner/karma/blob/master/CHANGELOG.md)
- [Commits](https://github.com/karma-runner/karma/compare/v6.0.0...v6.0.1)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump @angular/cli from 11.0.7 to 11.1.1 in /console (#1201)

Bumps [@angular/cli](https://github.com/angular/angular-cli) from 11.0.7 to 11.1.1.
- [Release notes](https://github.com/angular/angular-cli/releases)
- [Commits](https://github.com/angular/angular-cli/compare/v11.0.7...v11.1.1)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump @types/jasmine from 3.6.2 to 3.6.3 in /console (#1200)

Bumps [@types/jasmine](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jasmine) from 3.6.2 to 3.6.3.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/jasmine)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Max Peintner <max@caos.ch>

* chore(deps-dev): bump @types/node from 14.14.21 to 14.14.22 in /console (#1199)

Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 14.14.21 to 14.14.22.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump @angular-devkit/build-angular in /console (#1198)

Bumps [@angular-devkit/build-angular](https://github.com/angular/angular-cli) from 0.1100.7 to 0.1101.1.
- [Release notes](https://github.com/angular/angular-cli/releases)
- [Commits](https://github.com/angular/angular-cli/commits)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Max Peintner <max@caos.ch>

* chore(deps): bump angularx-qrcode from 10.0.11 to 11.0.0 in /console (#1197)

Bumps [angularx-qrcode](https://github.com/cordobo/angularx-qrcode) from 10.0.11 to 11.0.0.
- [Release notes](https://github.com/cordobo/angularx-qrcode/releases)
- [Commits](https://github.com/cordobo/angularx-qrcode/compare/10.0.11...11.0.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* fix pack lock

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* fix: handle sequence correctly in subscription (#1209)

* fix: correct master after merges again (#1230)

* chore(docs): correct `iss` claim of jwt profile (#1229)

* core(docs): correct `iss` claim of jwt profile

* fix: correct master after merges again (#1230)

* feat(login): new palette based styles (#1149)

* chore(deps-dev): bump rollup from 2.33.2 to 2.34.0 in /site (#1040)

Bumps [rollup](https://github.com/rollup/rollup) from 2.33.2 to 2.34.0.
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v2.33.2...v2.34.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps): bump svelte-i18n from 3.2.5 to 3.3.0 in /site (#1039)

Bumps [svelte-i18n](https://github.com/kaisermann/svelte-i18n) from 3.2.5 to 3.3.0.
- [Release notes](https://github.com/kaisermann/svelte-i18n/releases)
- [Changelog](https://github.com/kaisermann/svelte-i18n/blob/main/CHANGELOG.md)
- [Commits](https://github.com/kaisermann/svelte-i18n/compare/v3.2.5...v3.3.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump @rollup/plugin-url from 5.0.1 to 6.0.0 in /site (#1038)

Bumps [@rollup/plugin-url](https://github.com/rollup/plugins) from 5.0.1 to 6.0.0.
- [Release notes](https://github.com/rollup/plugins/releases)
- [Commits](https://github.com/rollup/plugins/compare/url-v5.0.1...url-v6.0.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump svelte from 3.29.7 to 3.30.1 in /site (#1037)

Bumps [svelte](https://github.com/sveltejs/svelte) from 3.29.7 to 3.30.1.
- [Release notes](https://github.com/sveltejs/svelte/releases)
- [Changelog](https://github.com/sveltejs/svelte/blob/master/CHANGELOG.md)
- [Commits](https://github.com/sveltejs/svelte/compare/v3.29.7...v3.30.1)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps): bump marked from 1.2.4 to 1.2.5 in /site (#1036)

Bumps [marked](https://github.com/markedjs/marked) from 1.2.4 to 1.2.5.
- [Release notes](https://github.com/markedjs/marked/releases)
- [Changelog](https://github.com/markedjs/marked/blob/master/release.config.js)
- [Commits](https://github.com/markedjs/marked/compare/v1.2.4...v1.2.5)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump @babel/core from 7.12.3 to 7.12.9 in /site (#1035)

Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.12.3 to 7.12.9.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.12.9/packages/babel-core)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump rollup-plugin-svelte from 6.1.1 to 7.0.0 in /site (#1034)

Bumps [rollup-plugin-svelte](https://github.com/sveltejs/rollup-plugin-svelte) from 6.1.1 to 7.0.0.
- [Release notes](https://github.com/sveltejs/rollup-plugin-svelte/releases)
- [Changelog](https://github.com/sveltejs/rollup-plugin-svelte/blob/master/CHANGELOG.md)
- [Commits](https://github.com/sveltejs/rollup-plugin-svelte/compare/v6.1.1...v7.0.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump @rollup/plugin-commonjs in /site (#1033)

Bumps [@rollup/plugin-commonjs](https://github.com/rollup/plugins) from 15.1.0 to 17.0.0.
- [Release notes](https://github.com/rollup/plugins/releases)
- [Commits](https://github.com/rollup/plugins/compare/commonjs-v15.1.0...commonjs-v17.0.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump @rollup/plugin-node-resolve in /site (#1032)

Bumps [@rollup/plugin-node-resolve](https://github.com/rollup/plugins) from 10.0.0 to 11.0.0.
- [Release notes](https://github.com/rollup/plugins/releases)
- [Commits](https://github.com/rollup/plugins/compare/node-resolve-v10.0.0...commonjs-v11.0.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump @babel/preset-env from 7.12.1 to 7.12.7 in /site (#1031)

Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.12.1 to 7.12.7.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.12.7/packages/babel-preset-env)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* go

* bundle files, lgn-color, legacy theme

* remove old references

* light dark context, button styles, zitadel brand

* button theme, edit templates

* typography theme mixins

* input styles, container, extend light dark palette

* footer, palette, container

* container, label, assets, header

* action container, input, typography label, adapt button theme

* a and footer styles, adapt palette

* user log profile, resourcetempurl

* postinstall againnn

* wrochage

* rm local grpc

* button elevation, helper for components

* radio

* radio button mixins, bundle

* qr code styles, secret clipboard, icon pack

* stroked buttons, icon buttons, header action, typography

* fix password policy styles

* account selection

* account selection, lgn avatar

* mocks

* template fixes, animations scss

* checkbox, register temp

* checkbox appr

* fix checkbox, remove input interference

* select theme

* avatar script, user selection, password policy validation fix

* fix formfield state for register and change pwd

* footer, main style, qr code fix, mfa type fix, account sel, checkbox

* fotter tos, user select

* reverse buttons for intial submit action

* theme script, themed error messages, header img source

* content wrapper, i18n, mobile

* emptyline

* idp mixins, fix unstyled html

* register container

* register layout, list themes, policy theme, register org

* massive asset cleanup

* fix source path, add missing icon, fix complexity refs, prefix

* remove material icons, unused assets, fix icon font

* move icon pack

* avatar, contrast theme, error fix

* zitadel css map

* revert go mod

* fix mfa verify actions

* add idp styles

* fix google colors, idp styles

* fix: bugs

* fix register options, google

* fix script, mobile layout

* precompile font selection

* go mod tidy

* assets and cleanup

* input suffix, fix alignment, actions, add progress bar themes

* progress bar mixins, layout fixes

* remove test from loginname

* cleanup comments, scripts

* clear comments

* fix external back button

* fix mfa alignment

* fix actions layout, on dom change listener for suffix

* free tier change, success label

* fix: button font line-height

* remove tabindex

* remove comment

* remove comment

* Update internal/ui/login/handler/password_handler.go

Co-authored-by: Livio Amstutz <livio.a@gmail.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Maximilian Peintner <csaq7175@uibk.ac.at>
Co-authored-by: Livio Amstutz <livio.a@gmail.com>

* chore(console): dependencies (#1233)

* chore(deps-dev): bump @angular-devkit/build-angular in /console (#1214)

Bumps [@angular-devkit/build-angular](https://github.com/angular/angular-cli) from 0.1101.1 to 0.1101.2.
- [Release notes](https://github.com/angular/angular-cli/releases)
- [Commits](https://github.com/angular/angular-cli/commits)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump karma from 6.0.1 to 6.0.3 in /console (#1215)

Bumps [karma](https://github.com/karma-runner/karma) from 6.0.1 to 6.0.3.
- [Release notes](https://github.com/karma-runner/karma/releases)
- [Changelog](https://github.com/karma-runner/karma/blob/master/CHANGELOG.md)
- [Commits](https://github.com/karma-runner/karma/compare/v6.0.1...v6.0.3)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump @angular/language-service in /console (#1216)

Bumps [@angular/language-service](https://github.com/angular/angular/tree/HEAD/packages/language-service) from 11.1.0 to 11.1.1.
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/master/CHANGELOG.md)
- [Commits](https://github.com/angular/angular/commits/11.1.1/packages/language-service)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump @angular/cli from 11.1.1 to 11.1.2 in /console (#1217)

Bumps [@angular/cli](https://github.com/angular/angular-cli) from 11.1.1 to 11.1.2.
- [Release notes](https://github.com/angular/angular-cli/releases)
- [Commits](https://github.com/angular/angular-cli/compare/v11.1.1...v11.1.2)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Max Peintner <max@caos.ch>

* lock

* site deps

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* fix: get email texts with default language (#1238)

* fix(login): mail verification (#1237)

* fix: mail verification

* not block, stroked

* fix: issues of new login ui (#1241)

* fix: i18n of register

* fix: autofocus

* feat(operator): zitadel and database operator (#1208)

* feat(operator): add base for zitadel operator

* fix(operator): changed pipeline to release operator

* fix(operator): fmt with only one parameter

* fix(operator): corrected workflow job name

* fix(zitadelctl): added restore and backuplist command

* fix(zitadelctl): scale for restore

* chore(container): use scratch for deploy container

* fix(zitadelctl): limit image to scratch

* fix(migration): added migration scripts for newer version

* fix(operator): changed handling of kubeconfig in operator logic

* fix(operator): changed handling of secrets in operator logic

* fix(operator): use new version of zitadel

* fix(operator): added path for migrations

* fix(operator): delete doublets of migration scripts

* fix(operator): delete subpaths and integrate logic into init container

* fix(operator): corrected path in dockerfile for local migrations

* fix(operator): added migrations for cockroachdb-secure

* fix(operator): delete logic for ambassador module

* fix(operator): added read and write secret commands

* fix(operator): correct and align operator pipeline with zitadel pipeline

* fix(operator): correct yaml error in operator pipeline

* fix(operator): correct action name in operator pipeline

* fix(operator): correct case-sensitive filename in operator pipeline

* fix(operator): upload artifacts from buildx output

* fix(operator): corrected attribute spelling error

* fix(operator): combined jobs for operator binary and image

* fix(operator): added missing comma in operator pipeline

* fix(operator): added codecov for operator image

* fix(operator): added codecov for operator image

* fix(testing): code changes for testing and several unit-tests (#1009)

* fix(operator): usage of interface of kubernetes client for testing and several unit-tests

* fix(operator): several unit-tests

* fix(operator): several unit-tests

* fix(operator): changed order for the operator logic

* fix(operator): added version of zitadelctl from semantic release

* fix(operator): corrected function call with version of zitadelctl

* fix(operator): corrected function call with version of zitadelctl

* fix(operator): add check output to operator release pipeline

* fix(operator): set --short length everywhere to 12

* fix(operator): zitadel setup in job instead of exec with several unit tests

* fix(operator): fixes to combine newest zitadel and testing branch

* fix(operator): corrected path in Dockerfile

* fix(operator): fixed unit-test that was ignored during changes

* fix(operator): fixed unit-test that was ignored during changes

* fix(operator): corrected Dockerfile to correctly use env variable

* fix(operator): quickfix takeoff deployment

* fix(operator): corrected the clusterrolename in the applied artifacts

* fix: update secure migrations

* fix(operator): migrations (#1057)

* fix(operator): copied migrations from orbos repository

* fix(operator): newest migrations

* chore: use cockroach-secure

* fix: rename migration

* fix: remove insecure cockroach migrations

Co-authored-by: Stefan Benz <stefan@caos.ch>

* fix: finalize labels

* fix(operator): cli logging concurrent and fixe deployment of operator during restore

* fix: finalize labels and cli commands

* fix: restore

* chore: cockroachdb is always secure

* chore: use orbos consistent-labels latest commit

* test: make tests compatible with new labels

* fix: default to sa token for start command

* fix: use cockroachdb v12.02

* fix: don't delete flyway user

* test: fix migration test

* fix: use correct table qualifiers

* fix: don't alter sequence ownership

* fix: upgrade flyway

* fix: change ownership of all dbs and tables to admin user

* fix: change defaultdb user

* fix: treat clientid status codes >= 400 as errors

* fix: reconcile specified ZITADEL version, not binary version

* fix: add ca-certs

* fix: use latest orbos code

* fix: use orbos with fixed race condition

* fix: use latest ORBOS code

* fix: use latest ORBOS code

* fix: make migration and scaling around restoring work

* fix(operator): move zitadel operator

* chore(migrations): include owner change migration

* feat(db): add code base for database operator

* fix(db): change used image registry for database operator

* fix(db): generated mock

* fix(db): add accidentally ignored file

* fix(db): add cockroachdb backup image to pipeline

* fix(db): correct pipeline and image versions

* fix(db): correct version of used orbos

* fix(db): correct database import

* fix(db): go mod tidy

* fix(db): use new version for orbos

* fix(migrations): include migrations into zitadelctl binary (#1211)

* fix(db): use statik to integrate migrations into binary

* fix(migrations): corrections unit tests and pipeline for integrated migrations into zitadelctl binary

* fix(migrations): correction in dockerfile for pipeline build

* fix(migrations): correction in dockerfile for pipeline build

* fix(migrations):  dockerfile changes for cache optimization

* fix(database): correct used part-of label in database operator

* fix(database): correct used selectable label in zitadel operator

* fix(operator): correct lables for user secrets in zitadel operator

* fix(operator): correct lables for service test in zitadel operator

* fix: don't enable database features for user operations (#1227)

* fix: don't enable database features for user operations

* fix: omit database feature for connection info adapter

* fix: use latest orbos version

* fix: update ORBOS (#1240)

Co-authored-by: Florian Forster <florian@caos.ch>
Co-authored-by: Elio Bischof <eliobischof@gmail.com>

* chore: add local migrate_local.go again (#1261)

* chore: pass params in migrate_local.go (#1264)

* fix: login policy bug (#1268)

* fix: permissions on login policy multifactors and secondfactors

* fix idp restriction

Co-authored-by: Max Peintner <max@caos.ch>

* fix: redirect after idp create (#1269)

* fix(pipeline): corrected and combined operator and zitadel release into combined workflow (#1273)

* fix(pipeline): combined operator and zitadel workflow to only release once

* fix(pipeline): add dev releases for zitadelctl

* fix(pipeline): delete unused name attribute

* fix(pipeline): corrected use of github token env-variable

* fix(pipeline): corrected download of artifacts to globally defined folder

* fix(pipeline): corrected download of artifacts to globally defined folder

* fix(pipeline): corrected ref to get branch name for release

* fix(pipeline): last corrections and use of different github action (#1270)

* fix(pipeline): corrected loop for dev release

* fix(pipeline): exclude tags from starting build workflow

* fix(pipeline): use different release create action for already existing release

* fix(pipeline): use correct name for release

* fix(pipeline): push image with branch name tag and replace slashes with underscores

* fix(pipeline): corrected indenting for yaml syntax

* fix(pipeline): corrected handling of branch name

* fix(pipeline): list artifacts after download

* fix(pipeline): use github env for artifacts folder

* fix(pipeline): replace slash with underscore in all jobs

* fix(pipeline): pre-calculate refs for all jobs

* fix(pipeline): corrected yaml indenting

* fix(pipeline): deleted missed step

* fix(pipeline): deleted unexpected input for dev-release

* fix(pipeline): corrected echo for version in refs job

* fix(pipeline): remove empty if in job

* chore(pipeline): use correct path to zitadelctl binaries (#1277)

* fix(pipeline): use correct version for zitadelctl build (#1278)

* fix: usermemberships in authz (#1288)

* fix: usermemberships in authz

* fix: tests

* fix: migration

* fix: handler

* fix: my usermemberships (#1290)

* fix: my usermemberships

* frontend

Co-authored-by: Max Peintner <max@caos.ch>

* fix: my usermemberships (#1291)

* fix: my usermemberships

* fix: migration

* fix: migration (#1293)

* fix(login): chrome prefill, org register suffix offset, loginname overflow (#1292)

* fix: calculate offset, fix prefill

* fix loginname, displayname overflow

* feat: docs rehaul, fix missing context in console, quickstarts (#1212)

* onboarding components, routing, steps

* onboarding component, toc

* fix onboarding mixin

* header

* refactor docs

* fix layout

* cleanup routing

* docs routing

* fix conventions

* de en routing

* docs, guide contents, nav

* rem i18n support

* fix routing from docs

* rollup onwarn changes, preload

* update svelte plugin, update rollup config

* move docs

* revert img style, remove code table

* rem de completely

* rollup optim, template

* angular quickstart, quickstart overview page, update deps

* fix link

* pack, slug

* prefetch binding, hidden links

* export log

* guards route ch

* fix homepage

* angular docs

* docs

* resolve fsh

* overview

* docs

* docs

* packages fix race condition

* nav, home link

* add vue, aspnet

* doc optimizations

* embed status pal

* angular guide

* angular guide

* dotnet, angular guide

* viewbox

* typo

* block onboarding route for non iam writers

* set links from component data

* fix: fetch org context in guard, more main cnt (#1192)

* change get started guide, fix code blockquotes, typos

* flutter guide

* h2 spacing

* highlight strong

* plus

* rm start sublinks

* add proxy quickstart

* regex

* prevent outside click, fix project grant write

Co-authored-by: Florian Forster <florian@caos.ch>
Co-authored-by: Livio Amstutz <livio.a@gmail.com>

* fix(console): auth guard, i18n (#1296)

* fix: auth guard, i18n

* Update console/src/app/guards/auth.guard.ts

Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>

* feat(console): OIDC setup (#1272)

* feat: delete app

* radio button mods, i18n

* radio style, recommended flag

* fix form, emitter, module, styles

* app oidc

* form value change

* cleanup

* app grid, new app detail, redirect, i18n

* new uri format

* seperate uris

* cleanup export, create redirect

* fix custom two way binding, switch

* chore(deps): bump grpc from 1.24.3 to 1.24.5 in /console (#1287)

* chore: add local migrate_local.go again (#1261)

* chore: pass params in migrate_local.go (#1264)

* fix: login policy bug (#1268)

* fix: permissions on login policy multifactors and secondfactors

* fix idp restriction

Co-authored-by: Max Peintner <max@caos.ch>

* fix: redirect after idp create (#1269)

* fix(pipeline): corrected and combined operator and zitadel release into combined workflow (#1273)

* fix(pipeline): combined operator and zitadel workflow to only release once

* fix(pipeline): add dev releases for zitadelctl

* fix(pipeline): delete unused name attribute

* fix(pipeline): corrected use of github token env-variable

* fix(pipeline): corrected download of artifacts to globally defined folder

* fix(pipeline): corrected download of artifacts to globally defined folder

* fix(pipeline): corrected ref to get branch name for release

* fix(pipeline): last corrections and use of different github action (#1270)

* fix(pipeline): corrected loop for dev release

* fix(pipeline): exclude tags from starting build workflow

* fix(pipeline): use different release create action for already existing release

* fix(pipeline): use correct name for release

* fix(pipeline): push image with branch name tag and replace slashes with underscores

* fix(pipeline): corrected indenting for yaml syntax

* fix(pipeline): corrected handling of branch name

* fix(pipeline): list artifacts after download

* fix(pipeline): use github env for artifacts folder

* fix(pipeline): replace slash with underscore in all jobs

* fix(pipeline): pre-calculate refs for all jobs

* fix(pipeline): corrected yaml indenting

* fix(pipeline): deleted missed step

* fix(pipeline): deleted unexpected input for dev-release

* fix(pipeline): corrected echo for version in refs job

* fix(pipeline): remove empty if in job

* chore(pipeline): use correct path to zitadelctl binaries (#1277)

* fix(pipeline): use correct version for zitadelctl build (#1278)

* chore(deps): bump grpc from 1.24.3 to 1.24.5 in /console

Bumps [grpc](https://github.com/grpc/grpc-node) from 1.24.3 to 1.24.5.
- [Release notes](https://github.com/grpc/grpc-node/releases)
- [Commits](https://github.com/grpc/grpc-node/compare/grpc@1.24.3...grpc@1.24.5)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: Livio Amstutz <livio.a@gmail.com>
Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>
Co-authored-by: Max Peintner <max@caos.ch>
Co-authored-by: Stefan Benz <46600784+stebenz@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump @types/node from 14.14.22 to 14.14.28 in /console (#1286)

* chore: add local migrate_local.go again (#1261)

* chore: pass params in migrate_local.go (#1264)

* fix: login policy bug (#1268)

* fix: permissions on login policy multifactors and secondfactors

* fix idp restriction

Co-authored-by: Max Peintner <max@caos.ch>

* fix: redirect after idp create (#1269)

* fix(pipeline): corrected and combined operator and zitadel release into combined workflow (#1273)

* fix(pipeline): combined operator and zitadel workflow to only release once

* fix(pipeline): add dev releases for zitadelctl

* fix(pipeline): delete unused name attribute

* fix(pipeline): corrected use of github token env-variable

* fix(pipeline): corrected download of artifacts to globally defined folder

* fix(pipeline): corrected download of artifacts to globally defined folder

* fix(pipeline): corrected ref to get branch name for release

* fix(pipeline): last corrections and use of different github action (#1270)

* fix(pipeline): corrected loop for dev release

* fix(pipeline): exclude tags from starting build workflow

* fix(pipeline): use different release create action for already existing release

* fix(pipeline): use correct name for release

* fix(pipeline): push image with branch name tag and replace slashes with underscores

* fix(pipeline): corrected indenting for yaml syntax

* fix(pipeline): corrected handling of branch name

* fix(pipeline): list artifacts after download

* fix(pipeline): use github env for artifacts folder

* fix(pipeline): replace slash with underscore in all jobs

* fix(pipeline): pre-calculate refs for all jobs

* fix(pipeline): corrected yaml indenting

* fix(pipeline): deleted missed step

* fix(pipeline): deleted unexpected input for dev-release

* fix(pipeline): corrected echo for version in refs job

* fix(pipeline): remove empty if in job

* chore(pipeline): use correct path to zitadelctl binaries (#1277)

* fix(pipeline): use correct version for zitadelctl build (#1278)

* chore(deps-dev): bump @types/node from 14.14.22 to 14.14.28 in /console

Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 14.14.22 to 14.14.28.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: Livio Amstutz <livio.a@gmail.com>
Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>
Co-authored-by: Max Peintner <max@caos.ch>
Co-authored-by: Stefan Benz <46600784+stebenz@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump @angular-devkit/build-angular from 0.1101.2 to 0.1102.0 in /console (#1285)

* chore: add local migrate_local.go again (#1261)

* chore: pass params in migrate_local.go (#1264)

* fix: login policy bug (#1268)

* fix: permissions on login policy multifactors and secondfactors

* fix idp restriction

Co-authored-by: Max Peintner <max@caos.ch>

* fix: redirect after idp create (#1269)

* fix(pipeline): corrected and combined operator and zitadel release into combined workflow (#1273)

* fix(pipeline): combined operator and zitadel workflow to only release once

* fix(pipeline): add dev releases for zitadelctl

* fix(pipeline): delete unused name attribute

* fix(pipeline): corrected use of github token env-variable

* fix(pipeline): corrected download of artifacts to globally defined folder

* fix(pipeline): corrected download of artifacts to globally defined folder

* fix(pipeline): corrected ref to get branch name for release

* fix(pipeline): last corrections and use of different github action (#1270)

* fix(pipeline): corrected loop for dev release

* fix(pipeline): exclude tags from starting build workflow

* fix(pipeline): use different release create action for already existing release

* fix(pipeline): use correct name for release

* fix(pipeline): push image with branch name tag and replace slashes with underscores

* fix(pipeline): corrected indenting for yaml syntax

* fix(pipeline): corrected handling of branch name

* fix(pipeline): list artifacts after download

* fix(pipeline): use github env for artifacts folder

* fix(pipeline): replace slash with underscore in all jobs

* fix(pipeline): pre-calculate refs for all jobs

* fix(pipeline): corrected yaml indenting

* fix(pipeline): deleted missed step

* fix(pipeline): deleted unexpected input for dev-release

* fix(pipeline): corrected echo for version in refs job

* fix(pipeline): remove empty if in job

* chore(pipeline): use correct path to zitadelctl binaries (#1277)

* fix(pipeline): use correct version for zitadelctl build (#1278)

* chore(deps-dev): bump @angular-devkit/build-angular in /console

Bumps [@angular-devkit/build-angular](https://github.com/angular/angular-cli) from 0.1101.2 to 0.1102.0.
- [Release notes](https://github.com/angular/angular-cli/releases)
- [Commits](https://github.com/angular/angular-cli/commits)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: Livio Amstutz <livio.a@gmail.com>
Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>
Co-authored-by: Max Peintner <max@caos.ch>
Co-authored-by: Stefan Benz <46600784+stebenz@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump typescript from 4.0.5 to 4.0.7 in /console (#1284)

* chore: add local migrate_local.go again (#1261)

* chore: pass params in migrate_local.go (#1264)

* fix: login policy bug (#1268)

* fix: permissions on login policy multifactors and secondfactors

* fix idp restriction

Co-authored-by: Max Peintner <max@caos.ch>

* fix: redirect after idp create (#1269)

* fix(pipeline): corrected and combined operator and zitadel release into combined workflow (#1273)

* fix(pipeline): combined operator and zitadel workflow to only release once

* fix(pipeline): add dev releases for zitadelctl

* fix(pipeline): delete unused name attribute

* fix(pipeline): corrected use of github token env-variable

* fix(pipeline): corrected download of artifacts to globally defined folder

* fix(pipeline): corrected download of artifacts to globally defined folder

* fix(pipeline): corrected ref to get branch name for release

* fix(pipeline): last corrections and use of different github action (#1270)

* fix(pipeline): corrected loop for dev release

* fix(pipeline): exclude tags from starting build workflow

* fix(pipeline): use different release create action for already existing release

* fix(pipeline): use correct name for release

* fix(pipeline): push image with branch name tag and replace slashes with underscores

* fix(pipeline): corrected indenting for yaml syntax

* fix(pipeline): corrected handling of branch name

* fix(pipeline): list artifacts after download

* fix(pipeline): use github env for artifacts folder

* fix(pipeline): replace slash with underscore in all jobs

* fix(pipeline): pre-calculate refs for all jobs

* fix(pipeline): corrected yaml indenting

* fix(pipeline): deleted missed step

* fix(pipeline): deleted unexpected input for dev-release

* fix(pipeline): corrected echo for version in refs job

* fix(pipeline): remove empty if in job

* chore(pipeline): use correct path to zitadelctl binaries (#1277)

* fix(pipeline): use correct version for zitadelctl build (#1278)

* chore(deps-dev): bump typescript from 4.0.5 to 4.0.7 in /console

Bumps [typescript](https://github.com/Microsoft/TypeScript) from 4.0.5 to 4.0.7.
- [Release notes](https://github.com/Microsoft/TypeScript/releases)
- [Commits](https://github.com/Microsoft/TypeScript/compare/v4.0.5...v4.0.7)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: Livio Amstutz <livio.a@gmail.com>
Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>
Co-authored-by: Max Peintner <max@caos.ch>
Co-authored-by: Stefan Benz <46600784+stebenz@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump karma from 6.0.3 to 6.1.1 in /console (#1283)

* chore: add local migrate_local.go again (#1261)

* chore: pass params in migrate_local.go (#1264)

* fix: login policy bug (#1268)

* fix: permissions on login policy multifactors and secondfactors

* fix idp restriction

Co-authored-by: Max Peintner <max@caos.ch>

* fix: redirect after idp create (#1269)

* fix(pipeline): corrected and combined operator and zitadel release into combined workflow (#1273)

* fix(pipeline): combined operator and zitadel workflow to only release once

* fix(pipeline): add dev releases for zitadelctl

* fix(pipeline): delete unused name attribute

* fix(pipeline): corrected use of github token env-variable

* fix(pipeline): corrected download of artifacts to globally defined folder

* fix(pipeline): corrected download of artifacts to globally defined folder

* fix(pipeline): corrected ref to get branch name for release

* fix(pipeline): last corrections and use of different github action (#1270)

* fix(pipeline): corrected loop for dev release

* fix(pipeline): exclude tags from starting build workflow

* fix(pipeline): use different release create action for already existing release

* fix(pipeline): use correct name for release

* fix(pipeline): push image with branch name tag and replace slashes with underscores

* fix(pipeline): corrected indenting for yaml syntax

* fix(pipeline): corrected handling of branch name

* fix(pipeline): list artifacts after download

* fix(pipeline): use github env for artifacts folder

* fix(pipeline): replace slash with underscore in all jobs

* fix(pipeline): pre-calculate refs for all jobs

* fix(pipeline): corrected yaml indenting

* fix(pipeline): deleted missed step

* fix(pipeline): deleted unexpected input for dev-release

* fix(pipeline): corrected echo for version in refs job

* fix(pipeline): remove empty if in job

* chore(pipeline): use correct path to zitadelctl binaries (#1277)

* fix(pipeline): use correct version for zitadelctl build (#1278)

* chore(deps-dev): bump karma from 6.0.3 to 6.1.1 in /console

Bumps [karma](https://github.com/karma-runner/karma) from 6.0.3 to 6.1.1.
- [Release notes](https://github.com/karma-runner/karma/releases)
- [Changelog](https://github.com/karma-runner/karma/blob/master/CHANGELOG.md)
- [Commits](https://github.com/karma-runner/karma/compare/v6.0.3...v6.1.1)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: Livio Amstutz <livio.a@gmail.com>
Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>
Co-authored-by: Max Peintner <max@caos.ch>
Co-authored-by: Stefan Benz <46600784+stebenz@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump @angular/language-service from 11.1.1 to 11.2.0 in /console (#1282)

* chore: add local migrate_local.go again (#1261)

* chore: pass params in migrate_local.go (#1264)

* fix: login policy bug (#1268)

* fix: permissions on login policy multifactors and secondfactors

* fix idp restriction

Co-authored-by: Max Peintner <max@caos.ch>

* fix: redirect after idp create (#1269)

* fix(pipeline): corrected and combined operator and zitadel release into combined workflow (#1273)

* fix(pipeline): combined operator and zitadel workflow to only release once

* fix(pipeline): add dev releases for zitadelctl

* fix(pipeline): delete unused name attribute

* fix(pipeline): corrected use of github token env-variable

* fix(pipeline): corrected download of artifacts to globally defined folder

* fix(pipeline): corrected download of artifacts to globally defined folder

* fix(pipeline): corrected ref to get branch name for release

* fix(pipeline): last corrections and use of different github action (#1270)

* fix(pipeline): corrected loop for dev release

* fix(pipeline): exclude tags from starting build workflow

* fix(pipeline): use different release create action for already existing release

* fix(pipeline): use correct name for release

* fix(pipeline): push image with branch name tag and replace slashes with underscores

* fix(pipeline): corrected indenting for yaml syntax

* fix(pipeline): corrected handling of branch name

* fix(pipeline): list artifacts after download

* fix(pipeline): use github env for artifacts folder

* fix(pipeline): replace slash with underscore in all jobs

* fix(pipeline): pre-calculate refs for all jobs

* fix(pipeline): corrected yaml indenting

* fix(pipeline): deleted missed step

* fix(pipeline): deleted unexpected input for dev-release

* fix(pipeline): corrected echo for version in refs job

* fix(pipeline): remove empty if in job

* chore(pipeline): use correct path to zitadelctl binaries (#1277)

* fix(pipeline): use correct version for zitadelctl build (#1278)

* chore(deps-dev): bump @angular/language-service in /console

Bumps [@angular/language-service](https://github.com/angular/angular/tree/HEAD/packages/language-service) from 11.1.1 to 11.2.0.
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/master/CHANGELOG.md)
- [Commits](https://github.com/angular/angular/commits/11.2.0/packages/language-service)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: Livio Amstutz <livio.a@gmail.com>
Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>
Co-authored-by: Max Peintner <max@caos.ch>
Co-authored-by: Stefan Benz <46600784+stebenz@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump stylelint from 13.9.0 to 13.10.0 in /console (#1281)

* chore: add local migrate_local.go again (#1261)

* chore: pass params in migrate_local.go (#1264)

* fix: login policy bug (#1268)

* fix: permissions on login policy multifactors and secondfactors

* fix idp restriction

Co-authored-by: Max Peintner <max@caos.ch>

* fix: redirect after idp create (#1269)

* fix(pipeline): corrected and combined operator and zitadel release into combined workflow (#1273)

* fix(pipeline): combined operator and zitadel workflow to only release once

* fix(pipeline): add dev releases for zitadelctl

* fix(pipeline): delete unused name attribute

* fix(pipeline): corrected use of github token env-variable

* fix(pipeline): corrected download of artifacts to globally defined folder

* fix(pipeline): corrected download of artifacts to globally defined folder

* fix(pipeline): corrected ref to get branch name for release

* fix(pipeline): last corrections and use of different github action (#1270)

* fix(pipeline): corrected loop for dev release

* fix(pipeline): exclude tags from starting build workflow

* fix(pipeline): use different release create action for already existing release

* fix(pipeline): use correct name for release

* fix(pipeline): push image with branch name tag and replace slashes with underscores

* fix(pipeline): corrected indenting for yaml syntax

* fix(pipeline): corrected handling of branch name

* fix(pipeline): list artifacts after download

* fix(pipeline): use github env for artifacts folder

* fix(pipeline): replace slash with underscore in all jobs

* fix(pipeline): pre-calculate refs for all jobs

* fix(pipeline): corrected yaml indenting

* fix(pipeline): deleted missed step

* fix(pipeline): deleted unexpected input for dev-release

* fix(pipeline): corrected echo for version in refs job

* fix(pipeline): remove empty if in job

* chore(pipeline): use correct path to zitadelctl binaries (#1277)

* fix(pipeline): use correct version for zitadelctl build (#1278)

* chore(deps-dev): bump stylelint from 13.9.0 to 13.10.0 in /console

Bumps [stylelint](https://github.com/stylelint/stylelint) from 13.9.0 to 13.10.0.
- [Release notes](https://github.com/stylelint/stylelint/releases)
- [Changelog](https://github.com/stylelint/stylelint/blob/master/CHANGELOG.md)
- [Commits](https://github.com/stylelint/stylelint/compare/13.9.0...13.10.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: Livio Amstutz <livio.a@gmail.com>
Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>
Co-authored-by: Max Peintner <max@caos.ch>
Co-authored-by: Stefan Benz <46600784+stebenz@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump @angular/cli from 11.1.2 to 11.2.0 in /console (#1280)

* chore: add local migrate_local.go again (#1261)

* chore: pass params in migrate_local.go (#1264)

* fix: login policy bug (#1268)

* fix: permissions on login policy multifactors and secondfactors

* fix idp restriction

Co-authored-by: Max Peintner <max@caos.ch>

* fix: redirect after idp create (#1269)

* fix(pipeline): corrected and combined operator and zitadel release into combined workflow (#1273)

* fix(pipeline): combined operator and zitadel workflow to only release once

* fix(pipeline): add dev releases for zitadelctl

* fix(pipeline): delete unused name attribute

* fix(pipeline): corrected use of github token env-variable

* fix(pipeline): corrected download of artifacts to globally defined folder

* fix(pipeline): corrected download of artifacts to globally defined folder

* fix(pipeline): corrected ref to get branch name for release

* fix(pipeline): last corrections and use of different github action (#1270)

* fix(pipeline): corrected loop for dev release

* fix(pipeline): exclude tags from starting build workflow

* fix(pipeline): use different release create action for already existing release

* fix(pipeline): use correct name for release

* fix(pipeline): push image with branch name tag and replace slashes with underscores

* fix(pipeline): corrected indenting for yaml syntax

* fix(pipeline): corrected handling of branch name

* fix(pipeline): list artifacts after download

* fix(pipeline): use github env for artifacts folder

* fix(pipeline): replace slash with underscore in all jobs

* fix(pipeline): pre-calculate refs for all jobs

* fix(pipeline): corrected yaml indenting

* fix(pipeline): deleted missed step

* fix(pipeline): deleted unexpected input for dev-release

* fix(pipeline): corrected echo for version in refs job

* fix(pipeline): remove empty if in job

* chore(pipeline): use correct path to zitadelctl binaries (#1277)

* fix(pipeline): use correct version for zitadelctl build (#1278)

* chore(deps-dev): bump @angular/cli from 11.1.2 to 11.2.0 in /console

Bumps [@angular/cli](https://github.com/angular/angular-cli) from 11.1.2 to 11.2.0.
- [Release notes](https://github.com/angular/angular-cli/releases)
- [Commits](https://github.com/angular/angular-cli/compare/v11.1.2...v11.2.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: Livio Amstutz <livio.a@gmail.com>
Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>
Co-authored-by: Max Peintner <max@caos.ch>
Co-authored-by: Stefan Benz <46600784+stebenz@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump stylelint-scss from 3.18.0 to 3.19.0 in /console (#1279)

* chore: add local migrate_local.go again (#1261)

* chore: pass params in migrate_local.go (#1264)

* fix: login policy bug (#1268)

* fix: permissions on login policy multifactors and secondfactors

* fix idp restriction

Co-authored-by: Max Peintner <max@caos.ch>

* fix: redirect after idp create (#1269)

* fix(pipeline): corrected and combined operator and zitadel release into combined workflow (#1273)

* fix(pipeline): combined operator and zitadel workflow to only release once

* fix(pipeline): add dev releases for zitadelctl

* fix(pipeline): delete unused name attribute

* fix(pipeline): corrected use of github token env-variable

* fix(pipeline): corrected download of artifacts to globally defined folder

* fix(pipeline): corrected download of artifacts to globally defined folder

* fix(pipeline): corrected ref to get branch name for release

* fix(pipeline): last corrections and use of different github action (#1270)

* fix(pipeline): corrected loop for dev release

* fix(pipeline): exclude tags from starting build workflow

* fix(pipeline): use different release create action for already existing release

* fix(pipeline): use correct name for release

* fix(pipeline): push image with branch name tag and replace slashes with underscores

* fix(pipeline): corrected indenting for yaml syntax

* fix(pipeline): corrected handling of branch name

* fix(pipeline): list artifacts after download

* fix(pipeline): use github env for artifacts folder

* fix(pipeline): replace slash with underscore in all jobs

* fix(pipeline): pre-calculate refs for all jobs

* fix(pipeline): corrected yaml indenting

* fix(pipeline): deleted missed step

* fix(pipeline): deleted unexpected input for dev-release

* fix(pipeline): corrected echo for version in refs job

* fix(pipeline): remove empty if in job

* chore(pipeline): use correct path to zitadelctl binaries (#1277)

* fix(pipeline): use correct version for zitadelctl build (#1278)

* chore(deps-dev): bump stylelint-scss from 3.18.0 to 3.19.0 in /console

Bumps [stylelint-scss](https://github.com/kristerkari/stylelint-scss) from 3.18.0 to 3.19.0.
- [Release notes](https://github.com/kristerkari/stylelint-scss/releases)
- [Changelog](https://github.com/kristerkari/stylelint-scss/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kristerkari/stylelint-scss/compare/3.18.0...3.19.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: Livio Amstutz <livio.a@gmail.com>
Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>
Co-authored-by: Max Peintner <max@caos.ch>
Co-authored-by: Stefan Benz <46600784+stebenz@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* fix custom change, highlight current config, links

* info app-detail

* app card component

* applications list, fix project-grant-owner

* fix member write

* colorize warn in app

* redirect warnings

* Update console/src/assets/i18n/de.json

Co-authored-by: Livio Amstutz <livio.a@gmail.com>

* Update console/src/assets/i18n/de.json

Co-authored-by: Livio Amstutz <livio.a@gmail.com>

* Update console/src/assets/i18n/en.json

Co-authored-by: Livio Amstutz <livio.a@gmail.com>

* Update console/src/assets/i18n/de.json

Co-authored-by: Livio Amstutz <livio.a@gmail.com>

* Update console/src/assets/i18n/de.json

Co-authored-by: Livio Amstutz <livio.a@gmail.com>

* Update console/src/assets/i18n/de.json

Co-authored-by: Livio Amstutz <livio.a@gmail.com>

* Update console/src/assets/i18n/de.json

Co-authored-by: Livio Amstutz <livio.a@gmail.com>

* remove comments

* Update console/src/assets/i18n/de.json

Co-authored-by: Livio Amstutz <livio.a@gmail.com>

* Update console/src/assets/i18n/de.json

Co-authored-by: Livio Amstutz <livio.a@gmail.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Livio Amstutz <livio.a@gmail.com>
Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>
Co-authored-by: Stefan Benz <46600784+stebenz@users.noreply.github.com>

* fix: primary button color (#1297)

* fix: remove status, admin line width (#1298)

* feat: token introspection, api clients and auth method private_key_jwt (#1276)

* introspect

* testingapplication key

* date

* client keys

* fix client keys

* fix client keys

* access tokens only for users

* AuthMethodPrivateKeyJWT

* client keys

* set introspection info correctly

* managae apis

* update oidc pkg

* cleanup

* merge msater

* set current sequence in migration

* set current sequence in migration

* set current sequence in migration

* Apply suggestions from code review

Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>

* DeleteAuthNKeysByObjectID

* ensure authn keys uptodate

* update oidc version

* merge master

* merge master

Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>

* merge master

* fix: version of migration for auth keys

* merge master

* merge master

* fix step 11

Co-authored-by: Max Peintner <max@caos.ch>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Michael Waeger <49439088+michaelulrichwaeger@users.noreply.github.com>
Co-authored-by: Maximilian Peintner <csaq7175@uibk.ac.at>
Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>
Co-authored-by: Stefan Benz <46600784+stebenz@users.noreply.github.com>
Co-authored-by: Florian Forster <florian@caos.ch>
Co-authored-by: Elio Bischof <eliobischof@gmail.com>
This commit is contained in:
Livio Amstutz
2021-02-18 13:41:55 +01:00
committed by GitHub
parent ee86eb4399
commit 027a6386c0
316 changed files with 9632 additions and 4919 deletions

View File

@@ -1,91 +0,0 @@
name: Zitadel Release
on: push
env:
GITHUB_TOKEN: ${{ secrets.CR_PAT }}
REGISTRY: ghcr.io
NODE_VERSION: '12'
GO_VERSION: '1.15'
jobs:
container:
runs-on: ubuntu-18.04
steps:
- name: Source checkout
uses: actions/checkout@v2
- name: Set output
id: branch
run: echo ::set-output name=short_ref::${GITHUB_REF#refs/*/}
- name: Check output
run: echo ${{ steps.branch.outputs.short_ref }}
- name: Generate Short SHA Container Tag
id: vars
run: echo "::set-output name=sha_short::SHA-$(git rev-parse --short=12 HEAD)"
- name: Cache Docker layers
uses: actions/cache@v2
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Login to DockerHub
uses: docker/login-action@v1
with:
username: ${{ github.actor }}
password: ${{ secrets.CR_PAT }}
registry: ${{ env.REGISTRY }}
- uses: docker/build-push-action@v2
with:
context: .
file: ./build/dockerfile
platforms: linux/amd64
tags: ${{ env.REGISTRY }}/${{ github.repository }}:${{ steps.vars.outputs.sha_short }},${{ env.REGISTRY }}/${{ github.repository }}:${{ steps.branch.outputs.short_ref }}
push: true
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,mode=max,dest=/tmp/.buildx-cache
release:
runs-on: ubuntu-18.04
needs: [container]
env:
DOCKER_USERNAME: ${{ github.actor }}
DOCKER_PASSWORD: ${{ secrets.CR_PAT }}
steps:
- name: Source checkout
uses: actions/checkout@v2
- name: Generate Short SHA Container Tag
id: vars
run: echo "::set-output name=sha_short::SHA-$(git rev-parse --short=12 HEAD)"
- name: Docker Login
run: docker login $REGISTRY -u $GITHUB_ACTOR -p $GITHUB_TOKEN
- name: Docker Pull short-sha
run: docker pull $REGISTRY/$GITHUB_REPOSITORY:${{ steps.vars.outputs.sha_short }}
- name: Semantic Release
id: semantic
uses: cycjimmy/semantic-release-action@v2
with:
dry_run: false
semantic_version: 17.0.4
- name: Do something when a new release published
if: steps.semantic.outputs.new_release_published == 'true'
run: |
echo ${{ steps.semantic.outputs.new_release_version }}
echo ${{ steps.semantic.outputs.new_release_major_version }}
echo ${{ steps.semantic.outputs.new_release_minor_version }}
echo ${{ steps.semantic.outputs.new_release_patch_version }}
- name: Docker Tag Version
run: docker tag $REGISTRY/$GITHUB_REPOSITORY:${{ steps.vars.outputs.sha_short }} $REGISTRY/$GITHUB_REPOSITORY:${{ steps.semantic.outputs.new_release_version }}
if: steps.semantic.outputs.new_release_published == 'true'
- name: Docker Tag Latest
run: docker tag $REGISTRY/$GITHUB_REPOSITORY:${{ steps.vars.outputs.sha_short }} $REGISTRY/$GITHUB_REPOSITORY:latest
if: steps.semantic.outputs.new_release_published == 'true'
- name: Docker Push Version
run: docker push $REGISTRY/$GITHUB_REPOSITORY:${{ steps.semantic.outputs.new_release_version }}
if: steps.semantic.outputs.new_release_published == 'true'
- name: Docker Push Latest
run: docker push $REGISTRY/$GITHUB_REPOSITORY:latest
if: steps.semantic.outputs.new_release_published == 'true'

View File

@@ -6,15 +6,15 @@ module.exports = {
["@semantic-release/github", { ["@semantic-release/github", {
"assets": [ "assets": [
{ {
"path": ".artifacts/zitadel-darwin-amd64/zitadelctl", "path": "./artifacts/zitadelctl-darwin-amd64/zitadelctl-darwin-amd64",
"label": "Zitadelctl Darwin x86_64" "label": "Zitadelctl Darwin x86_64"
}, },
{ {
"path": ".artifacts/zitadel-linux-amd64/zitadelctl", "path": "./artifacts/zitadelctl-linux-amd64/zitadelctl-linux-amd64",
"label": "Zitadelctl Linux x86_64" "label": "Zitadelctl Linux x86_64"
}, },
{ {
"path": ".artifacts/zitadel-windows-amd64/zitadelctl", "path": "./artifacts/zitadelctl-windows-amd64/zitadelctl-windows-amd64.exe",
"label": "Zitadelctl Windows x86_64" "label": "Zitadelctl Windows x86_64"
} }
] ]

View File

@@ -88,7 +88,7 @@ SetUp:
Step6: Step6:
DefaultLabelPolicy: DefaultLabelPolicy:
PrimaryColor: '#222324' PrimaryColor: '#222324'
SecondaryColor: '#ffffff' SecondaryColor: '#ffffff'
Step7: Step7:
OTP: true OTP: true
Step8: Step8:
@@ -180,4 +180,4 @@ SetUp:
Text: The domain {{.Domain}} has been claimed by an organisation. Your current user {{.Username}} is not part of this organisation. Therefore you'll have to change your email when you login. We have created a temporary username ({{.TempUsername}}) for this login. Text: The domain {{.Domain}} has been claimed by an organisation. Your current user {{.Username}} is not part of this organisation. Therefore you'll have to change your email when you login. We have created a temporary username ({{.TempUsername}}) for this login.
ButtonText: Login ButtonText: Login
Step11: Step11:
MigrateV1EventstoreToV2: true MigrateV1EventstoreToV2: $ZITADEL_MIGRATE_ES_V1

View File

@@ -17,6 +17,7 @@ Metrics:
MeterName: 'github.com/caos/zitadel' MeterName: 'github.com/caos/zitadel'
AuthZ: AuthZ:
Domain: $ZITADEL_DEFAULT_DOMAIN
Repository: Repository:
Eventstore: Eventstore:
ServiceName: 'AuthZ' ServiceName: 'AuthZ'
@@ -186,6 +187,7 @@ API:
Issuer: $ZITADEL_ISSUER Issuer: $ZITADEL_ISSUER
DefaultLogoutRedirectURI: $ZITADEL_ACCOUNTS/logout/done DefaultLogoutRedirectURI: $ZITADEL_ACCOUNTS/logout/done
CodeMethodS256: true CodeMethodS256: true
AuthMethodPrivateKeyJWT: true
StorageConfig: StorageConfig:
DefaultLoginURL: $ZITADEL_ACCOUNTS/login?authRequestID= DefaultLoginURL: $ZITADEL_ACCOUNTS/login?authRequestID=
DefaultAccessTokenLifetime: 12h DefaultAccessTokenLifetime: 12h
@@ -207,6 +209,9 @@ API:
Token: Token:
Path: 'token' Path: 'token'
URL: '$ZITADEL_OAUTH/token' URL: '$ZITADEL_OAUTH/token'
Introspection:
Path: 'introspect'
URL: '$ZITADEL_OAUTH/introspect'
EndSession: EndSession:
Path: 'endsession' Path: 'endsession'
URL: '$ZITADEL_AUTHORIZE/endsession' URL: '$ZITADEL_AUTHORIZE/endsession'

View File

@@ -45,6 +45,7 @@ SystemDefaults:
IncludeDigits: true IncludeDigits: true
IncludeSymbols: false IncludeSymbols: false
MachineKeySize: 2048 MachineKeySize: 2048
ClientKeySize: 2048
Multifactors: Multifactors:
OTP: OTP:
Issuer: 'ZITADEL' Issuer: 'ZITADEL'

3781
console/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -33,7 +33,7 @@
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"google-proto-files": "^2.4.0", "google-proto-files": "^2.4.0",
"google-protobuf": "^3.13.0", "google-protobuf": "^3.13.0",
"grpc": "^1.24.3", "grpc": "^1.24.5",
"grpc-web": "^1.2.1", "grpc-web": "^1.2.1",
"moment": "^2.29.1", "moment": "^2.29.1",
"ngx-quicklink": "^0.2.6", "ngx-quicklink": "^0.2.6",
@@ -44,28 +44,28 @@
"zone.js": "~0.11.3" "zone.js": "~0.11.3"
}, },
"devDependencies": { "devDependencies": {
"@angular/cli": "~11.1.2", "@angular/cli": "~11.2.0",
"@angular-devkit/build-angular": "~0.1101.2", "@angular-devkit/build-angular": "~0.1102.0",
"@angular/compiler-cli": "~11.0.0", "@angular/compiler-cli": "~11.0.0",
"@types/jasmine": "~3.6.3", "@types/jasmine": "~3.6.3",
"@angular/language-service": "~11.1.1", "@angular/language-service": "~11.2.0",
"@types/jasminewd2": "~2.0.3", "@types/jasminewd2": "~2.0.3",
"@types/node": "^14.14.22", "@types/node": "^14.14.28",
"codelyzer": "^6.0.0", "codelyzer": "^6.0.0",
"jasmine-core": "~3.6.0", "jasmine-core": "~3.6.0",
"jasmine-spec-reporter": "~6.0.0", "jasmine-spec-reporter": "~6.0.0",
"karma": "~6.0.3", "karma": "~6.1.1",
"karma-chrome-launcher": "~3.1.0", "karma-chrome-launcher": "~3.1.0",
"karma-coverage-istanbul-reporter": "~3.0.2", "karma-coverage-istanbul-reporter": "~3.0.2",
"karma-jasmine": "~4.0.0", "karma-jasmine": "~4.0.0",
"karma-jasmine-html-reporter": "^1.5.0", "karma-jasmine-html-reporter": "^1.5.0",
"prettier": "^2.2.1", "prettier": "^2.2.1",
"protractor": "~7.0.0", "protractor": "~7.0.0",
"stylelint": "^13.9.0", "stylelint": "^13.10.0",
"stylelint-config-standard": "^20.0.0", "stylelint-config-standard": "^20.0.0",
"stylelint-scss": "^3.18.0", "stylelint-scss": "^3.19.0",
"ts-node": "~9.1.1", "ts-node": "~9.1.1",
"tslint": "~6.1.3", "tslint": "~6.1.3",
"typescript": "^4.0.5" "typescript": "^4.0.7"
} }
} }

View File

@@ -11,6 +11,15 @@ const routes: Routes = [
loadChildren: () => import('./pages/home/home.module').then(m => m.HomeModule), loadChildren: () => import('./pages/home/home.module').then(m => m.HomeModule),
canActivate: [AuthGuard], canActivate: [AuthGuard],
}, },
{
path: 'firststeps',
loadChildren: () => import('./modules/onboarding/onboarding.module')
.then(m => m.OnboardingModule),
canActivate: [AuthGuard, RoleGuard],
data: {
roles: ['iam.write'],
}
},
{ {
path: 'granted-projects', path: 'granted-projects',
loadChildren: () => import('./pages/projects/granted-projects/granted-projects.module') loadChildren: () => import('./pages/projects/granted-projects/granted-projects.module')

View File

@@ -1,19 +1,25 @@
<ng-container *ngIf="(authService.user | async) || {} as user"> <ng-container *ngIf="(authService.user | async) || {} as user">
<ng-container *ngIf="((['iam.read$','iam.write$'] | hasRole)) as iamuser$"> <ng-container *ngIf="((['iam.read$','iam.write$'] | hasRole)) as iamuser$">
<mat-toolbar class="root-header"> <mat-toolbar class="root-header">
<button aria-label="Toggle sidenav" mat-icon-button (click)="drawer.toggle()"> <button *ngIf="authenticationService.authenticated" aria-label="Toggle sidenav" mat-icon-button
(click)="drawer.toggle()">
<i class="icon las la-bars"></i> <i class="icon las la-bars"></i>
</button> </button>
<a *ngIf="(isHandset$ | async) == false" class="title" [routerLink]="['/']"> <a class="title" [routerLink]="['/']">
<img class="logo" alt="zitadel logo" *ngIf="componentCssClass == 'dark-theme'; else lighttheme" <img class="logo" alt="zitadel logo" *ngIf="componentCssClass == 'dark-theme'; else lighttheme"
src="../assets/images/zitadel-logo-light.svg" /> src="../assets/images/zitadel-logo-solo-light.svg" />
<ng-template #lighttheme> <ng-template #lighttheme>
<img alt="zitadel logo" class="logo" src="../assets/images/zitadel-logo-dark.svg" /> <img alt="zitadel logo" class="logo" src="../assets/images/zitadel-logo-solo-dark.svg" />
</ng-template> </ng-template>
</a> </a>
<button (click)="loadOrgs()" *ngIf="profile?.id && org" mat-button [matMenuTriggerFor]="menu" <svg class="slash" viewBox="0 0 24 24" width="32" height="32" stroke="currentColor" stroke-width="1"
(menuOpened)="focusFilter()">{{org?.name ? org.name : 'NO NAME'}} stroke-linecap="round" stroke-linejoin="round" fill="none" shape-rendering="geometricPrecision">
<path d="M16.88 3.549L7.12 20.451"></path>
</svg>
<button class="org-button" (click)="loadOrgs()" *ngIf="profile?.id && org" mat-button
[matMenuTriggerFor]="menu" (menuOpened)="focusFilter()">{{org?.name ? org.name : 'NO NAME'}}
<mat-icon> <mat-icon>
arrow_drop_down</mat-icon> arrow_drop_down</mat-icon>
</button> </button>
@@ -37,8 +43,8 @@
</button> </button>
</div> </div>
<button class="show-all" mat-menu-item <button class="show-all" mat-menu-item [routerLink]="[ '/org/overview' ]">{{'MENU.SHOWORGS' |
[routerLink]="[ '/org/overview' ]">{{'MENU.SHOWORGS' | translate}}</button> translate}}</button>
<ng-template appHasRole [appHasRole]="['org.create','iam.write']"> <ng-template appHasRole [appHasRole]="['org.create','iam.write']">
<button mat-menu-item [routerLink]="[ '/org/create' ]"> <button mat-menu-item [routerLink]="[ '/org/create' ]">
@@ -49,23 +55,29 @@
</mat-menu> </mat-menu>
<span class="fill-space"></span> <span class="fill-space"></span>
<a class="doc-link" href="https://docs.zitadel.ch" mat-stroked-button <a class="doc-link" href="https://docs.zitadel.ch" mat-stroked-button target="_blank">{{'MENU.DOCUMENTATION'
target="_blank">{{'MENU.DOCUMENTATION' | translate}}</a> | translate}}</a>
<div (clickOutside)="closeAccountCard()" class="icon-container"> <div (clickOutside)="closeAccountCard()" class="icon-container">
<app-avatar *ngIf="user && (user.displayName || (user.firstName && user.lastName))" <app-avatar *ngIf="user && (user.displayName || (user.firstName && user.lastName))"
class="avatar dontcloseonclick" (click)="showAccount = !showAccount" [active]="showAccount" class="avatar dontcloseonclick" (click)="showAccount = !showAccount" [active]="showAccount"
[name]="user.displayName ? user.displayName : (user.firstName + ' '+ user.lastName)" [size]="38"> [name]="user.displayName ? user.displayName : (user.firstName + ' '+ user.lastName)" [size]="38">
</app-avatar> </app-avatar>
<app-accounts-card @accounts class="a_card mat-elevation-z5" *ngIf="showAccount" <app-accounts-card @accounts class="a_card mat-elevation-z1" *ngIf="showAccount"
(close)="showAccount = false" [profile]="profile" [iamuser]="iamuser$ | async"> (close)="showAccount = false" [profile]="profile" [iamuser]="iamuser$ | async">
</app-accounts-card> </app-accounts-card>
</div> </div>
</mat-toolbar> </mat-toolbar>
<mat-drawer-container class="main-container"> <mat-drawer-container class="main-container">
<mat-drawer #drawer class="sidenav" [mode]="(isHandset$ | async) ? 'over' : 'side'" <mat-drawer #drawer class="sidenav" [mode]="(isHandset$ | async) ? 'over' : 'side'"
[opened]="!(isHandset$ | async)"> [opened]="!(isHandset$ | async) && authenticationService.authenticated">
<div class="side-column"> <div class="side-column">
<div class="list"> <div class="list">
<a @navitem class="nav-item" [routerLinkActive]="['active']"
[routerLinkActiveOptions]="{ exact: true }" [routerLink]="['/']">
<i class="icon las la-home"></i>
<span class="label">{{ 'MENU.DASHBOARD' | translate }}</span>
</a>
<ng-container *ngIf="authenticationService.authenticationChanged | async"> <ng-container *ngIf="authenticationService.authenticationChanged | async">
<a @navitem matTooltip="{{'MENU.TOOLTIP.PERSONAL' | translate}}" class="nav-item" <a @navitem matTooltip="{{'MENU.TOOLTIP.PERSONAL' | translate}}" class="nav-item"
[routerLinkActive]="['active']" [routerLinkActiveOptions]="{ exact: true }" [routerLinkActive]="['active']" [routerLinkActiveOptions]="{ exact: true }"
@@ -163,6 +175,13 @@
</ng-container> </ng-container>
<span class="fill-space"></span> <span class="fill-space"></span>
<div class="toc-line">
<a class="toc" href="https://zitadel.ch/pdf/agb.pdf" alt="Terms and Conditions"
target="_blank">{{'MENU.TOC'
| translate}}</a>
<span>&nbsp;&nbsp;&nbsp;</span>
</div>
</div> </div>
<span class="fill-space"></span> <span class="fill-space"></span>
</div> </div>

View File

@@ -11,9 +11,14 @@
left: 0; left: 0;
right: 0; right: 0;
.org-button {
font-weight: bold;
padding-right: .5rem;
}
.logo { .logo {
max-height: 50px; max-height: 40px;
width: 160px; width: 40px;
} }
.title { .title {
@@ -22,7 +27,6 @@
font-size: 1.2rem; font-size: 1.2rem;
font-weight: 400; font-weight: 400;
line-height: 1.2rem; line-height: 1.2rem;
margin-right: 1rem;
} }
.context-menu { .context-menu {
@@ -82,7 +86,7 @@
padding-top: 60px; padding-top: 60px;
.sidenav { .sidenav {
width: 300px; width: 280px;
border-right: none; border-right: none;
.side-column { .side-column {
@@ -90,6 +94,7 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: stretch; align-items: stretch;
height: calc(100% - 60px);
.list { .list {
width: 100%; width: 100%;
@@ -123,7 +128,6 @@
.label { .label {
margin-bottom: 0; margin-bottom: 0;
font-size: 14px; font-size: 14px;
letter-spacing: .05em;
} }
.c_label { .c_label {
@@ -132,7 +136,6 @@
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
font-size: 14px; font-size: 14px;
letter-spacing: .03em;
.count { .count {
font-size: 12px; font-size: 12px;
@@ -140,7 +143,7 @@
} }
&:hover { &:hover {
background-color: #00000010; // background-color: #00000010;
border-top-right-radius: 1.5rem; border-top-right-radius: 1.5rem;
border-bottom-right-radius: 1.5rem; border-bottom-right-radius: 1.5rem;
} }
@@ -148,6 +151,7 @@
&.active { &.active {
border-top-right-radius: 1.5rem; border-top-right-radius: 1.5rem;
border-bottom-right-radius: 1.5rem; border-bottom-right-radius: 1.5rem;
font-weight: bold;
} }
} }
@@ -160,6 +164,43 @@
flex: 1 1 auto; flex: 1 1 auto;
} }
.toc-line {
margin: 2rem 2rem;
.toc {
font-size: 12px;
color: var(--grey);
text-decoration: none;
&:hover {
text-decoration: underline;
}
}
.sp-status {
font-size: 12px;
color: var(--grey);
text-decoration: none;
&:hover {
text-decoration: underline;
}
}
.sp-status .sp-status-badge.sp-status-ok {
background: darkgreen;
}
.sp-status .sp-status-badge.sp-status-scheduled {
background: darkblue;
}
.sp-status .sp-status-badge.sp-status-minor {
background: darkorange;
}
.sp-status .sp-status-badge.sp-status-major {
background: darkred;
}
}
.logout-button { .logout-button {
margin-bottom: 1rem; margin-bottom: 1rem;
} }

View File

@@ -251,7 +251,7 @@ export class AppComponent implements OnDestroy {
} }
private getProjectCount(): void { private getProjectCount(): void {
this.authService.isAllowed(['project.read$']).subscribe((allowed) => { this.authService.isAllowed(['project.read']).subscribe((allowed) => {
if (allowed) { if (allowed) {
this.mgmtService.SearchProjects(0, 0); this.mgmtService.SearchProjects(0, 0);

View File

@@ -23,6 +23,7 @@ import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader'; import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import { AuthConfig, OAuthModule, OAuthStorage } from 'angular-oauth2-oidc'; import { AuthConfig, OAuthModule, OAuthStorage } from 'angular-oauth2-oidc';
import { QuicklinkModule } from 'ngx-quicklink'; import { QuicklinkModule } from 'ngx-quicklink';
import { OnboardingModule } from 'src/app/modules/onboarding/onboarding.module';
import { RegExpPipeModule } from 'src/app/pipes/regexp-pipe/regexp-pipe.module'; import { RegExpPipeModule } from 'src/app/pipes/regexp-pipe/regexp-pipe.module';
import { environment } from '../environments/environment'; import { environment } from '../environments/environment';
@@ -121,6 +122,7 @@ const authConfig: AuthConfig = {
WarnDialogModule, WarnDialogModule,
MatDialogModule, MatDialogModule,
RegExpPipeModule, RegExpPipeModule,
OnboardingModule,
ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production }), ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production }),
], ],
providers: [ providers: [

View File

@@ -3,18 +3,19 @@ import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot } from '@angul
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { AuthenticationService } from '../services/authentication.service'; import { AuthenticationService } from '../services/authentication.service';
import { GrpcAuthService } from '../services/grpc-auth.service';
@Injectable({ @Injectable({
providedIn: 'root', providedIn: 'root',
}) })
export class AuthGuard implements CanActivate { export class AuthGuard implements CanActivate {
constructor(private auth: AuthenticationService) { } constructor(private auth: AuthenticationService, private authService: GrpcAuthService) { }
public canActivate( public canActivate(
_: ActivatedRouteSnapshot, _: ActivatedRouteSnapshot,
state: RouterStateSnapshot, state: RouterStateSnapshot,
): Observable<boolean> | Promise<boolean> | boolean { ): Observable<boolean> | Promise<boolean> | Promise<any> | boolean {
if (!this.auth.authenticated) { if (!this.auth.authenticated) {
return this.auth.authenticate(); return this.auth.authenticate();
} }

View File

@@ -0,0 +1,5 @@
<div class="cnsl-app-card" [ngClass]="{'web': type == OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB,
'useragent': type == OIDCApplicationType.OIDCAPPLICATIONTYPE_USER_AGENT,
'native': type == OIDCApplicationType.OIDCAPPLICATIONTYPE_NATIVE}">
<ng-content></ng-content>
</div>

View File

@@ -0,0 +1,49 @@
@import '~@angular/material/theming';
@mixin app-card-theme($theme) {
/* stylelint-disable */
$primary: map-get($theme, primary);
$primary-dark: mat-color($primary, A900);
$accent: map-get($theme, accent);
$is-dark-theme: map-get($theme, is-dark);
$accent-color: mat-color($primary, 500);
/* stylelint-enable */
.cnsl-app-card {
padding: 1rem;
box-sizing: border-box;
cursor: pointer;
animation: all .2s;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
font-size: 2rem;
height: 80px;
width: 80px;
margin: 1rem;
text-transform: uppercase;
border-radius: .5rem;
font-weight: 800;
background-color: $primary-dark;
transition: background-color box-shadow .3s ease-in;
&.web {
background-color: rgb(80, 110, 110);
color: white;
border: none;
}
&.native {
background-color: #595d80;
color: white;
border: none;
}
&.useragent {
background-color: #6a506e;
color: white;
border: none;
}
}
}

View File

@@ -0,0 +1,14 @@
import { Component, Input } from '@angular/core';
import { OIDCApplicationType } from 'src/app/proto/generated/management_pb';
@Component({
selector: 'cnsl-app-card',
templateUrl: './app-card.component.html',
styleUrls: ['./app-card.component.scss'],
})
export class AppCardComponent {
@Input() public outline: boolean = false;
@Input() public type!: OIDCApplicationType;
public OIDCApplicationType: any = OIDCApplicationType;
}

View File

@@ -0,0 +1,15 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { AppCardComponent } from './app-card.component';
@NgModule({
declarations: [AppCardComponent],
imports: [
CommonModule,
],
exports: [
AppCardComponent,
],
})
export class AppCardModule { }

View File

@@ -0,0 +1,35 @@
<div class="radio-button-wrapper">
<ng-container *ngFor="let method of authMethods; index as i">
<input type="radio" [disabled]="method.disabled" (change)="emitChange()" [value]="method.key" [id]="method.key"
[(ngModel)]="selected" />
<label class="cnsl-radio-button" [ngClass]="{'first': i == 0, 'last': i == authMethods.length - 1}"
[for]="method.key">
<div class="recommended" [ngClass]="{'not': method.notRecommended}"
*ngIf="method.recommended || method.notRecommended">
{{(method.recommended ?
'APP.OIDC.RECOMMENDED' : 'APP.OIDC.NOTRECOMMENDED') | translate }}</div>
<div class="cnsl-radio-header" [ngStyle]="{'background': method.background}">
<span>{{method.prefix}}</span>
<div class="current" *ngIf="current == method.key">{{'APP.OIDC.CURRENT' | translate}}</div>
</div>
<p>{{method.titleI18nKey | translate}}</p>
<p class="type-desc">{{method.descI18nKey | translate}}</p>
<span class="fill-space"></span>
<div class="app-specs">
<div class="row" *ngIf="method && method.responseType != undefined">
<span>{{'APP.OIDC.RESPONSE' | translate}}</span>
<span>{{('APP.OIDC.RESPONSE'+method.responseType.toString()) | translate}}</span>
</div>
<div class="row" *ngIf="method.grantType != undefined">
<span>{{'APP.GRANT' | translate}}</span>
<span>{{('APP.OIDC.GRANT'+method.grantType.toString()) | translate}}</span>
</div>
<div class="row" *ngIf="method.authMethod != undefined">
<span>{{'APP.OIDC.AUTHMETHOD' | translate}}</span>
<span>{{('APP.OIDC.AUTHMETHOD'+method.authMethod.toString()) | translate}}</span>
</div>
</div>
</label>
</ng-container>
</div>

View File

@@ -0,0 +1,140 @@
@import '~@angular/material/theming';
.radio-button-wrapper {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
overflow-x: auto;
overflow-y: hidden;
margin: 0;
padding-bottom: .5rem;
padding-top: 1rem;
}
@mixin app-auth-method-radio-theme($theme) {
$primary: map-get($theme, primary);
$primary-color: mat-color($primary, 500);
$is-dark-theme: map-get($theme, is-dark);
input[type="radio"]{
appearance: none;
opacity: 0;
display: none;
}
input:checked + label {
border-color: if($is-dark-theme, white, var(--grey));
.cnsl-radio-header span {
color: if($is-dark-theme, white, white);
}
}
.cnsl-radio-button {
margin: .5rem;
border-radius: .5rem;
border: 1px solid if($is-dark-theme, var(--grey), white);
display: flex;
flex-direction: column;
flex: 0 1 230px;
cursor: pointer;
position: relative;
padding-bottom: 1rem;
box-shadow: inset 0 0 6px rgba(0, 0, 0, .1);
&.first {
margin-left: 0;
}
&.last {
margin-right: 0;
}
.recommended {
position: absolute;
bottom: 0;
left: 50%;
transform: translateY(50%) translateX(-50%);
border-radius: 50vw;
font-size: 11px;
background: white;
color: black;
padding: 3px 1rem;
box-shadow: 0 0 6px rgb(0 0 0 / 10%);
white-space: nowrap;
&.not {
background: rgb(144 75 75);
color: white;
}
}
.cnsl-radio-header {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
background: rgb(80, 110, 110);
border-top-left-radius: 6px;
border-top-right-radius: 6px;
position: relative;
.current {
position: absolute;
bottom: .5rem;
left: 50%;
transform: translateX(-50%);
display: block;
color: #ffffff60;
white-space: nowrap;
font-size: 12px;
}
span {
margin: 2rem;
font-size: 30px;
color: if($is-dark-theme,#21222450, #ffffff50);
}
}
p {
text-align: center;
padding: 0 1rem;
}
.type-desc {
font-size: 14px;
color: var(--grey);
}
.fill-space {
flex: 1;
}
.app-specs {
display: block;
padding: 1rem 0;
margin: 0 1rem;
.row {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 12px;
color: var(--grey);
margin: 3px 0;
span {
white-space: nowrap;
}
:first-child {
margin-right: 1rem;
overflow: hidden;
text-overflow: ellipsis;
}
}
}
}
}

View File

@@ -0,0 +1,32 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { OIDCAuthMethodType, OIDCGrantType, OIDCResponseType } from 'src/app/proto/generated/management_pb';
export interface RadioItemAuthType {
key: string;
titleI18nKey: string;
descI18nKey: string;
disabled: boolean,
prefix: string;
background: string;
responseType?: OIDCResponseType;
grantType?: OIDCGrantType;
authMethod?: OIDCAuthMethodType;
recommended?: boolean;
notRecommended?: boolean;
}
@Component({
selector: 'app-auth-method-radio',
templateUrl: './app-auth-method-radio.component.html',
styleUrls: ['./app-auth-method-radio.component.scss'],
})
export class AppAuthMethodRadioComponent {
@Input() current: string = '';
@Input() selected: string = '';
@Input() authMethods!: RadioItemAuthType[];
@Output() selectedMethod: EventEmitter<string> = new EventEmitter();
public emitChange(): void {
this.selectedMethod.emit(this.selected);
}
}

View File

@@ -0,0 +1,27 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { MatRippleModule } from '@angular/material/core';
import { TranslateModule } from '@ngx-translate/core';
import { AppAuthMethodRadioComponent } from './app-auth-method-radio/app-auth-method-radio.component';
import { AppTypeRadioComponent } from './app-type-radio/app-type-radio.component';
@NgModule({
declarations: [
AppTypeRadioComponent,
AppAuthMethodRadioComponent,
],
imports: [
CommonModule,
FormsModule,
MatRippleModule,
TranslateModule,
],
exports: [
AppAuthMethodRadioComponent,
AppTypeRadioComponent,
],
})
export class AppRadioModule { }

View File

@@ -0,0 +1,14 @@
<div class="radio-button-wrapper">
<ng-container *ngFor="let type of types">
<input type="radio" [disabled]="type.disabled" (change)="emitChange()" [value]="type.type"
[(ngModel)]="selected" [id]="type.type" />
<label class="cnsl-type-radio-button" [for]="type.type">
<div class="cnsl-type-radio-header" [ngStyle]="{'background': type.background}">
<span>{{type.prefix}}</span>
</div>
<p>{{type.titleI18nKey | translate}}</p>
<p class="type-desc">{{type.descI18nKey | translate}}</p>
<span class="fill-space"></span>
</label>
</ng-container>
</div>

View File

@@ -0,0 +1,68 @@
@import '~@angular/material/theming';
.radio-button-wrapper {
display: flex;
flex-direction: row;
flex-wrap: wrap;
margin: 0 -0.5rem;
}
@mixin app-type-radio-theme($theme) {
$primary: map-get($theme, primary);
$primary-color: mat-color($primary, 500);
$is-dark-theme: map-get($theme, is-dark);
input[type="radio"]{
appearance: none;
opacity: 0;
display: none;
}
input:checked + label {
border-color: if($is-dark-theme, white, var(--grey));
.cnsl-type-radio-header span {
color: if($is-dark-theme, white, white);
}
}
.cnsl-type-radio-button {
margin: .5rem;
border-radius: .5rem;
border: 1px solid if($is-dark-theme, var(--grey), white);
display: flex;
flex-direction: column;
flex: 0 1 240px;
cursor: pointer;
position: relative;
padding-bottom: 1rem;
box-shadow: inset 0 0 6px rgba(0, 0, 0, .1);
.cnsl-type-radio-header {
display: flex;
align-items: center;
justify-content: center;
background: rgb(80, 110, 110);
margin-bottom: 1rem;
border-top-left-radius: 6px;
border-top-right-radius: 6px;
span {
margin: 2rem;
font-size: 30px;
color: if($is-dark-theme,#21222450, #ffffff50);
}
}
p {
text-align: center;
padding: 0 1rem;
}
.type-desc {
font-size: 14px;
color: var(--grey);
}
}
}

View File

@@ -0,0 +1,27 @@
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { OIDCApplicationType } from 'src/app/proto/generated/management_pb';
export interface RadioItemAppType {
type: OIDCApplicationType;
titleI18nKey: string;
descI18nKey: string;
checked: boolean,
disabled: boolean,
prefix: string;
background: string;
}
@Component({
selector: 'app-type-radio',
templateUrl: './app-type-radio.component.html',
styleUrls: ['./app-type-radio.component.scss'],
})
export class AppTypeRadioComponent {
@Input() selected: OIDCApplicationType = OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB;
@Input() types!: RadioItemAppType[];
@Output() selectedType: EventEmitter<OIDCApplicationType> = new EventEmitter();
public emitChange(): void {
this.selectedType.emit(this.selected);
}
}

View File

@@ -4,7 +4,8 @@
<h2 class="title">{{title}}</h2> <h2 class="title">{{title}}</h2>
<span class="fill-space"></span> <span class="fill-space"></span>
<ng-content select="[card-actions]"></ng-content> <ng-content select="[card-actions]"></ng-content>
<button class="button" matTooltip="Expand or collapse" mat-icon-button (click)="expanded = !expanded"> <button class="button" type="button" matTooltip="Expand or collapse" mat-icon-button
(click)="expanded = !expanded">
<mat-icon *ngIf="!expanded">keyboard_arrow_down</mat-icon> <mat-icon *ngIf="!expanded">keyboard_arrow_down</mat-icon>
<mat-icon *ngIf="expanded">keyboard_arrow_up</mat-icon> <mat-icon *ngIf="expanded">keyboard_arrow_up</mat-icon>
</button> </button>

View File

@@ -24,6 +24,8 @@
font-size: 16px; font-size: 16px;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: .05em; letter-spacing: .05em;
text-overflow: ellipsis;
overflow: hidden;
} }
.fill-space { .fill-space {

View File

@@ -18,7 +18,7 @@ import { Component, Input } from '@angular/core';
], ],
}) })
export class CardComponent { export class CardComponent {
public expanded: boolean = true; @Input() public expanded: boolean = true;
@Input() public title: string = ''; @Input() public title: string = '';
@Input() public description: string = ''; @Input() public description: string = '';
@Input() public animate: boolean = false; @Input() public animate: boolean = false;

View File

@@ -110,9 +110,9 @@ export class IdpCreateComponent implements OnInit, OnDestroy {
setTimeout(() => { setTimeout(() => {
this.loading = false; this.loading = false;
this.router.navigate([ this.router.navigate([
this.serviceType === PolicyComponentServiceType.MGMT ? 'org' : (this.serviceType === PolicyComponentServiceType.MGMT ? 'org' :
this.serviceType === PolicyComponentServiceType.ADMIN ? 'iam' : '', this.serviceType === PolicyComponentServiceType.ADMIN ? 'iam' : ''),
'idp', idp.getId()]); 'policy', 'login']);
}, 2000); }, 2000);
}).catch(error => { }).catch(error => {
this.toast.showError(error); this.toast.showError(error);

View File

@@ -1,6 +1,6 @@
<app-refresh-table [loading]="loading$ | async" (refreshed)="refreshPage()" [dataSize]="dataSource.data.length" <app-refresh-table [loading]="loading$ | async" (refreshed)="refreshPage()" [dataSize]="dataSource.data.length"
[emitRefreshOnPreviousRoutes]="['/iam/idp/create']" [timestamp]="idpResult?.viewTimestamp" [selection]="selection"> [emitRefreshOnPreviousRoutes]="['/iam/idp/create']" [timestamp]="idpResult?.viewTimestamp" [selection]="selection">
<ng-template appHasRole [appHasRole]="['iam.write']" actions> <div actions>
<button (click)="deactivateSelectedIdps()" matTooltip="{{'IDP.DEACTIVATE' | translate}}" class="icon-button" <button (click)="deactivateSelectedIdps()" matTooltip="{{'IDP.DEACTIVATE' | translate}}" class="icon-button"
mat-icon-button *ngIf="selection.hasValue()" [disabled]="disabled"> mat-icon-button *ngIf="selection.hasValue()" [disabled]="disabled">
<mat-icon>block</mat-icon> <mat-icon>block</mat-icon>
@@ -16,7 +16,7 @@
<a [routerLink]="createRouterLink" color="primary" mat-raised-button [disabled]="disabled"> <a [routerLink]="createRouterLink" color="primary" mat-raised-button [disabled]="disabled">
<mat-icon class="icon">add</mat-icon>{{ 'ACTIONS.NEW' | translate }} <mat-icon class="icon">add</mat-icon>{{ 'ACTIONS.NEW' | translate }}
</a> </a>
</ng-template> </div>
<div class="table-wrapper"> <div class="table-wrapper">
<table class="table" mat-table [dataSource]="dataSource"> <table class="table" mat-table [dataSource]="dataSource">

View File

@@ -1,5 +1,7 @@
<div class="info-section-row"> <div class="info-section-row" [ngClass]="{'info': type == 'INFO', 'warn': type == 'WARN'}">
<i class="icon las la-info"></i> <i *ngIf="type == 'INFO'" class="icon las la-info"></i>
<i *ngIf="type == 'WARN'" class="las la-exclamation"></i>
<div class="info-section-content"> <div class="info-section-content">
<ng-content></ng-content> <ng-content></ng-content>
</div> </div>

View File

@@ -7,24 +7,36 @@
.info-section-row { .info-section-row {
display: flex; display: flex;
background-color: if($is-dark-theme, #ffffff13, #f3f3f3);
border-radius: 4px; border-radius: 4px;
padding: .5rem 0; padding: .5rem 0;
padding-right: 1rem; padding-right: 1rem;
color: if($is-dark-theme, #d6d6d6, #3c4257);
font-size: 14px; font-size: 14px;
.icon { .icon {
margin-right: 1rem; margin-right: 1rem;
height: 1.2rem; height: 1.2rem;
line-height: 1.2rem; line-height: 1.2rem;
font-size: 1.2rem; font-size: 1.2rem;
margin-left: .5rem; margin-left: .5rem;
color: $primary-color;
} }
.info-section-content { .info-section-content {
flex: 1; flex: 1;
}
&.info {
background-color: if($is-dark-theme, #4f566b, #cbf4c9);
color: if($is-dark-theme, #cbf4c9, #0e6245);
.icon {
color: $primary-color;
}
}
&.warn {
background-color: if($is-dark-theme, #4f566b, #ffc1c1);
color: if($is-dark-theme, #ffc1c1, #620e0e);
} }
} }
} }

View File

@@ -1,8 +1,16 @@
import { Component } from '@angular/core'; import { Component, Input } from '@angular/core';
enum InfoSectionType {
INFO = 'INFO',
WARN = 'WARN',
}
@Component({ @Component({
selector: 'cnsl-info-section', selector: 'cnsl-info-section',
templateUrl: './info-section.component.html', templateUrl: './info-section.component.html',
styleUrls: ['./info-section.component.scss'], styleUrls: ['./info-section.component.scss'],
}) })
export class InfoSectionComponent { } export class InfoSectionComponent {
@Input() type = InfoSectionType.INFO;
}

View File

@@ -0,0 +1,18 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { OnboardingComponent } from './onboarding.component';
const routes: Routes = [
{
path: '',
component: OnboardingComponent,
data: { animation: 'AddPage' },
},
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class OnboardingRoutingModule { }

View File

@@ -0,0 +1,27 @@
<div class="split">
<div class="left">
<p class="firststeps">{{'ONBOARDING.HEADER' | translate}}</p>
<h1>{{'ONBOARDING.TITLE' | translate}}</h1>
</div>
<div class="right">
<p class="desc">{{'ONBOARDING.DESCRIPTION' | translate}}</p>
<h2>{{'ONBOARDING.STEPS_TITLE' | translate}}</h2>
<div class="onboarding-row" *ngFor="let step of steps; index as i">
<div class="prev">{{i + 1}}</div>
<div>
<h3>{{step.titleI18nKey | translate}}</h3>
<p>{{step.descI18nKey | translate}}</p>
</div>
<span class="fill-space"></span>
<div class="action-row">
<a *ngIf="step?.docs" [href]="step.docs" alt="Zitadel Docs" target="_blank"
class="goto docs">{{'ONBOARDING.DOCS' |
translate}}
<i class="las la-external-link-alt"></i>
</a>
<a *ngIf="step.link" class="goto" [routerLink]="step.link">{{'ONBOARDING.START' | translate}}</a>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,147 @@
@import '~@angular/material/theming';
@mixin onboarding-theme($theme) {
/* stylelint-disable */
$primary: map-get($theme, primary);
$primary-color: mat-color($primary, 500);
$is-dark-theme: map-get($theme, is-dark);
/* stylelint-enable */
.onboarding-row {
box-shadow: inset 0 -1px if($is-dark-theme, #303131, #e3e8ee);
.prev {
background: $primary-color;
}
.goto {
text-decoration: none;
background: white;
border: 1px solid if($is-dark-theme, #303131, #e3e8ee);
&.docs {
background-color: $primary-color;
i {
font-size: 1rem;
margin-left: 3px;
}
}
}
}
}
.split {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
display: flex;
flex-direction: column;
box-sizing: border-box;
border-radius: 0.5rem;
box-shadow: 0 3px 8px 0 rgb(0 0 0 / 6%);
@media only screen and (min-width: 1024px) {
flex-direction: row;
.right {
overflow: auto;
}
}
.left {
flex-basis: 300px;
box-sizing: border-box;
padding: 1.5rem;
background: linear-gradient(40deg, rgb(80, 66, 121),rgb(177, 59, 122),rgb(225,53,81), rgb(230,107,86));
box-shadow: inset -2px 1px 15px -9px #000000;
h1 {
color: white;
}
.firststeps {
color: #fad6e3;
text-transform: uppercase;
font-size: 12px;
font-weight: bold;
}
p {
color: #fad6e3;
font-size: 12px;
font-weight: bold;
}
button {
width: 100%;
}
}
.right {
padding: 1.5rem;
flex: 1;
box-sizing: border-box;
.desc {
color: var(--grey);
font-size: 20px;
margin-top: .5rem;
}
.onboarding-row {
display: flex;
padding: 1rem 0;
align-items: center;
.prev {
height: 40px;
width: 40px;
min-width: 40px;
border-radius: .5rem;
display: flex;
align-items: center;
justify-content: center;
margin-right: 2rem;
color: white;
font-size: 1.2rem;
box-shadow: 0 3px 8px 0 rgb(0 0 0 / 6%);
}
h3 {
margin-top: 0;
margin-bottom: .5rem;
font-size: 15px;
}
p {
font-size: 12px;
margin: 0;
color: var(--grey);
}
.fill-space {
flex: 1;
}
.action-row {
display: flex;
align-items: center;
flex-wrap: wrap;
justify-content: flex-end;
.goto {
background-color: white;
padding: 2px 1rem;
color: black;
border-radius: 50vw;
font-size: 12px;
margin: .5rem 0 .5rem 1rem;
white-space: nowrap;
}
}
}
}
}

View File

@@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { OnboardingComponent } from './onboarding.component';
describe('OnboardingComponent', () => {
let component: OnboardingComponent;
let fixture: ComponentFixture<OnboardingComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ OnboardingComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(OnboardingComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,16 @@
import { Component, OnInit } from '@angular/core';
import { AuthenticationService } from 'src/app/services/authentication.service';
@Component({
selector: 'cnsl-onboarding',
templateUrl: './onboarding.component.html',
styleUrls: ['./onboarding.component.scss']
})
export class OnboardingComponent {
public steps = [
{ titleI18nKey: 'ONBOARDING.STEPS.1.TITLE', descI18nKey: 'ONBOARDING.STEPS.1.DESC', docs: "https://docs.zitadel.ch/use", link: ['/projects', 'create'] },
{ titleI18nKey: 'ONBOARDING.STEPS.2.TITLE', descI18nKey: 'ONBOARDING.STEPS.2.DESC', docs: "https://docs.zitadel.ch/use", link: ['/projects'] },
{ titleI18nKey: 'ONBOARDING.STEPS.3.TITLE', descI18nKey: 'ONBOARDING.STEPS.3.DESC', link: ['/iam', 'policies'] },
];
constructor() { }
}

View File

@@ -0,0 +1,18 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { TranslateModule } from '@ngx-translate/core';
import { OnboardingRoutingModule } from './onboarding-routing.module';
import { OnboardingComponent } from './onboarding.component';
@NgModule({
declarations: [OnboardingComponent],
imports: [
CommonModule,
TranslateModule,
OnboardingRoutingModule,
MatButtonModule,
],
})
export class OnboardingModule { }

View File

@@ -73,14 +73,14 @@
<p class="subdesc">{{ 'MFA.LIST.MULTIFACTORDESCRIPTION' | translate }}</p> <p class="subdesc">{{ 'MFA.LIST.MULTIFACTORDESCRIPTION' | translate }}</p>
<app-mfa-table [service]="service" [serviceType]="serviceType" <app-mfa-table [service]="service" [serviceType]="serviceType"
[componentType]="LoginMethodComponentType.MultiFactor" [componentType]="LoginMethodComponentType.MultiFactor"
[disabled]="([serviceType == PolicyComponentServiceType.ADMIN ? 'iam.policy.write' : serviceType == PolicyComponentServiceType.MGMT ? 'iam.policy.write' : ''] | hasRole | async) == false"> [disabled]="([serviceType == PolicyComponentServiceType.ADMIN ? 'iam.policy.write' : serviceType == PolicyComponentServiceType.MGMT ? 'policy.write' : ''] | hasRole | async) == false">
</app-mfa-table> </app-mfa-table>
<h3 class="subheader">{{ 'MFA.LIST.SECONDFACTORTITLE' | translate }}</h3> <h3 class="subheader">{{ 'MFA.LIST.SECONDFACTORTITLE' | translate }}</h3>
<p class="subdesc">{{ 'MFA.LIST.SECONDFACTORDESCRIPTION' | translate }}</p> <p class="subdesc">{{ 'MFA.LIST.SECONDFACTORDESCRIPTION' | translate }}</p>
<app-mfa-table [service]="service" [serviceType]="serviceType" <app-mfa-table [service]="service" [serviceType]="serviceType"
[componentType]="LoginMethodComponentType.SecondFactor" [componentType]="LoginMethodComponentType.SecondFactor"
[disabled]="([serviceType == PolicyComponentServiceType.ADMIN ? 'iam.policy.write' : serviceType == PolicyComponentServiceType.MGMT ? 'iam.policy.write' : ''] | hasRole | async) == false"> [disabled]="([serviceType == PolicyComponentServiceType.ADMIN ? 'iam.policy.write' : serviceType == PolicyComponentServiceType.MGMT ? 'policy.write' : ''] | hasRole | async) == false">
</app-mfa-table> </app-mfa-table>
</ng-container> </ng-container>

View File

@@ -16,12 +16,42 @@
</div> </div>
<div class="container"> <div class="container">
<ng-template appHasRole [appHasRole]="['iam.write']">
<a matRipple *ngIf="!firstStepsDismissed" class="onboard" [routerLink]="['/firststeps']">
<p class="first-steps">{{'ONBOARDING.HEADER' | translate}}</p>
<h2>{{'ONBOARDING.TITLE' | translate}}</h2>
<p class="desc">{{'ONBOARDING.DESCRIPTION' | translate}}</p>
<button matTooltip="{{'ACTIONS.CLOSE' | translate}}" (click)="dismissFirstSteps($event)" mat-icon-button
class="close">
<i class="las la-times"></i>
</button>
</a>
</ng-template>
<a matRipple *ngIf="!firstStepsDismissed" class="quickstart" target="_blank"
href="https://docs.zitadel.ch/quickstarts">
<p class="first-steps">{{'HOME.QUICKSTARTS.LABEL' | translate}}</p>
<h2>{{'HOME.QUICKSTARTS.TITLE' | translate}}</h2>
<p class="desc">{{'HOME.QUICKSTARTS.DESCRIPTION' | translate}}</p>
<div class="logo-cloud">
<i class="lab la-angular"></i>
<i class="lab la-react"></i>
<i class="lab la-android"></i>
<i class="lab la-app-store-ios"></i>
</div>
<button matTooltip="{{'ACTIONS.CLOSE' | translate}}" (click)="dismissQuickstarts($event)" mat-icon-button
class="close">
<i class="las la-times"></i>
</button>
</a>
<ng-template appHasRole [appHasRole]="['iam.write']"> <ng-template appHasRole [appHasRole]="['iam.write']">
<app-card class="item"> <app-card class="item">
<div class="top"> <div class="top">
<h2> <h2>
<i class="icon las la-gem"></i> <i class="icon las la-gem"></i>
{{'HOME.IAM'| translate}}</h2> {{'HOME.IAM'| translate}}
</h2>
<p>{{'HOME.IAM_DESC'| translate}}</p> <p>{{'HOME.IAM_DESC'| translate}}</p>
</div> </div>
@@ -30,15 +60,12 @@
class="las la-link"></i></a> class="las la-link"></i></a>
</ng-template> </ng-template>
<ng-template appHasRole [appHasRole]="['iam.policy.read']"> <ng-template appHasRole [appHasRole]="['iam.policy.read']">
<a class="short-link" <a class="short-link" [routerLink]="[ '/iam', 'policy','iam']">{{'HOME.IAM_POLICY_IAM' |
[routerLink]="[ '/iam', 'policy','iam']">{{'HOME.IAM_POLICY_IAM' | translate}}<i translate}}<i class="las la-link"></i></a>
class="las la-link"></i></a> <a class="short-link" [routerLink]="[ '/iam', 'policy','complexity']">{{'HOME.IAM_POLICY_COMPLEXITY'
<a class="short-link" | translate}}<i class="las la-link"></i></a>
[routerLink]="[ '/iam', 'policy','complexity']">{{'HOME.IAM_POLICY_COMPLEXITY' | translate}}<i <a class="short-link" [routerLink]="[ '/iam', 'policy','login']">{{'HOME.IAM_POLICY_LOGIN' |
class="las la-link"></i></a> translate}}<i class="las la-link"></i></a>
<a class="short-link"
[routerLink]="[ '/iam', 'policy','login']">{{'HOME.IAM_POLICY_LOGIN' | translate}}<i
class="las la-link"></i></a>
</ng-template> </ng-template>
<span class="fill-space"></span> <span class="fill-space"></span>
@@ -59,8 +86,8 @@
<span class="fill-space"></span> <span class="fill-space"></span>
<div class="footer"> <div class="footer">
<a color="primary" mat-stroked-button <a color="primary" mat-stroked-button [routerLink]="['/users/me']">{{'HOME.SECURITYANDPRIVACY_BUTTON' |
[routerLink]="['/users/me']">{{'HOME.SECURITYANDPRIVACY_BUTTON' | translate}}</a> translate}}</a>
</div> </div>
</app-card> </app-card>
@@ -69,18 +96,18 @@
<div class="top"> <div class="top">
<h2> <h2>
<i class="icon las la-layer-group"></i> <i class="icon las la-layer-group"></i>
{{'HOME.PROJECTS'| translate}}</h2> {{'HOME.PROJECTS'| translate}}
</h2>
<p>{{'HOME.PROJECTS_DESC'| translate}}</p> <p>{{'HOME.PROJECTS_DESC'| translate}}</p>
<ng-template appHasRole [appHasRole]="['project.create']"> <ng-template appHasRole [appHasRole]="['project.create']">
<a class="short-link" <a class="short-link" [routerLink]="[ '/projects', 'create']">{{'HOME.PROJECTS_NEW_LINK' |
[routerLink]="[ '/projects', 'create']">{{'HOME.PROJECTS_NEW_LINK' | translate}}<i translate}}<i class="las la-link"></i></a>
class="las la-link"></i></a>
</ng-template> </ng-template>
</div> </div>
<span class="fill-space"></span> <span class="fill-space"></span>
<div class="footer"> <div class="footer">
<a color="primary" mat-stroked-button <a color="primary" mat-stroked-button [routerLink]="['/projects']">{{'HOME.PROJECTS_BUTTON' |
[routerLink]="['/projects']">{{'HOME.PROJECTS_BUTTON' | translate}}</a> translate}}</a>
</div> </div>
</app-card> </app-card>
</ng-template> </ng-template>
@@ -92,23 +119,21 @@
{{'HOME.PROTECTION'| translate}}</h2> {{'HOME.PROTECTION'| translate}}</h2>
<p>{{'HOME.PROTECTION_DESC'| translate}}</p> <p>{{'HOME.PROTECTION_DESC'| translate}}</p>
<ng-template appHasRole [appHasRole]="['iam.policy.read']"> <ng-template appHasRole [appHasRole]="['iam.policy.read']">
<a class="short-link" <a class="short-link" [routerLink]="[ '/org', 'policy','iam']">{{'HOME.ORG_POLICY_IAM' |
[routerLink]="[ '/org', 'policy','iam']">{{'HOME.ORG_POLICY_IAM' | translate}}<i translate}}<i class="las la-link"></i></a>
class="las la-link"></i></a>
</ng-template> </ng-template>
<ng-template appHasRole [appHasRole]="['policy.read']"> <ng-template appHasRole [appHasRole]="['policy.read']">
<a class="short-link" <a class="short-link"
[routerLink]="[ '/org', 'policy','complexity']">{{'HOME.ORG_POLICY_COMPLEXITY' | translate}}<i [routerLink]="[ '/org', 'policy','complexity']">{{'HOME.ORG_POLICY_COMPLEXITY' |
class="las la-link"></i></a> translate}}<i class="las la-link"></i></a>
<a class="short-link" <a class="short-link" [routerLink]="[ '/org', 'policy','login']">{{'HOME.ORG_POLICY_LOGIN' |
[routerLink]="[ '/org', 'policy','login']">{{'HOME.ORG_POLICY_LOGIN' | translate}}<i translate}}<i class="las la-link"></i></a>
class="las la-link"></i></a>
</ng-template> </ng-template>
</div> </div>
<span class="fill-space"></span> <span class="fill-space"></span>
<div class="footer"> <div class="footer">
<a color="primary" mat-stroked-button <a color="primary" mat-stroked-button [routerLink]="['/org']">{{'HOME.PROTECTION_BUTTON' |
[routerLink]="['/org']">{{'HOME.PROTECTION_BUTTON' | translate}}</a> translate}}</a>
</div> </div>
</app-card> </app-card>
</ng-template> </ng-template>
@@ -118,15 +143,14 @@
<div class="top"> <div class="top">
<h2> <h2>
<i class="las la-users"></i> <i class="las la-users"></i>
{{'HOME.USERS'| translate}}</h2> {{'HOME.USERS'| translate}}
</h2>
<p>{{'HOME.USERS_DESC'| translate}}</p> <p>{{'HOME.USERS_DESC'| translate}}</p>
<ng-template appHasRole [appHasRole]="['user.read(:[0-9]*)?']"> <ng-template appHasRole [appHasRole]="['user.read(:[0-9]*)?']">
<a class="short-link" <a class="short-link" [routerLink]="[ '/users', 'list', 'humans']">{{'HOME.USERS_HUMANS' |
[routerLink]="[ '/users', 'list', 'humans']">{{'HOME.USERS_HUMANS' | translate}}<i translate}}<i class="las la-link"></i></a>
class="las la-link"></i></a> <a class="short-link" [routerLink]="[ '/users', 'list', 'machines']">{{'HOME.USERS_MACHINES' |
<a class="short-link" translate}}<i class="las la-link"></i></a>
[routerLink]="[ '/users', 'list', 'machines']">{{'HOME.USERS_MACHINES' | translate}}<i
class="las la-link"></i></a>
</ng-template> </ng-template>
<ng-template appHasRole [appHasRole]="['user.read']"> <ng-template appHasRole [appHasRole]="['user.read']">
<a class="short-link" [routerLink]="[ '/users', 'create']">{{'HOME.USERS_CREATE' | translate}}<i <a class="short-link" [routerLink]="[ '/users', 'create']">{{'HOME.USERS_CREATE' | translate}}<i
@@ -135,8 +159,8 @@
</div> </div>
<span class="fill-space"></span> <span class="fill-space"></span>
<div class="footer"> <div class="footer">
<a color="primary" mat-stroked-button <a color="primary" mat-stroked-button [routerLink]="['/users/list/humans']">{{'HOME.USERS_BUTTON' |
[routerLink]="['/users/list/humans']">{{'HOME.USERS_BUTTON' | translate}}</a> translate}}</a>
</div> </div>
</app-card> </app-card>
</ng-template> </ng-template>

View File

@@ -1,6 +1,7 @@
.wrapper { .wrapper {
padding-bottom: 100px; padding-bottom: 100px;
position: relative;
.header { .header {
display: flex; display: flex;
@@ -31,6 +32,78 @@
margin: -1rem; margin: -1rem;
justify-content: space-evenly; justify-content: space-evenly;
.onboard,
.quickstart {
text-decoration: none;
cursor: pointer;
box-sizing: border-box;
flex: 1 0 45%;
position: relative;
border-radius: 0.5rem;
margin: 1rem;
padding: 1.5rem;
box-shadow: 0 3px 8px 0 rgb(0 0 0 / 6%);
h2 {
color: white;
}
.first-steps {
text-transform: uppercase;
font-size: 12px;
font-weight: bold;
}
.close {
visibility: hidden;
position: absolute;
top: 0;
right: 0;
i {
color: white;
font-size: 1rem;
}
}
&:hover {
.close {
visibility: visible;
}
}
}
.onboard {
background: linear-gradient(40deg, rgb(80, 66, 121),rgb(177, 59, 122),rgb(225,53,81), rgb(230,107,86));
p {
color: #fad6e3;
}
}
.quickstart {
background: linear-gradient(30deg, #2283a6,#6c8f59);
p {
color: #d6f3fa;
}
.logo-cloud {
display: flex;
flex-wrap: wrap;
margin: -0.5rem;
i {
font-size: 40px;
padding: .5rem;
border: 1px solid #ffffff50;
border-radius: .5rem;
margin: 0.5rem;
color: white;
}
}
}
.item { .item {
flex: 1 0 45%; flex: 1 0 45%;
margin: 0 1rem; margin: 0 1rem;

View File

@@ -8,8 +8,26 @@ import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
}) })
export class HomeComponent { export class HomeComponent {
public dark: boolean = true; public dark: boolean = true;
public firstStepsDismissed: boolean = false;
public quickstartsDismissed: boolean = false;
constructor(public authService: GrpcAuthService) { constructor(public authService: GrpcAuthService) {
const theme = localStorage.getItem('theme'); const theme = localStorage.getItem('theme');
this.dark = theme === 'dark-theme' ? true : theme === 'light-theme' ? false : true; this.dark = theme === 'dark-theme' ? true : theme === 'light-theme' ? false : true;
this.firstStepsDismissed = localStorage.getItem('firstStartDismissed') == 'true' ? true : false;
this.quickstartsDismissed = localStorage.getItem('quickstartsDismissed') == 'true' ? true : false;
}
dismissFirstSteps(event: Event): void {
event.preventDefault();
localStorage.setItem('firstStartDismissed', 'true');
this.firstStepsDismissed = true;
}
dismissQuickstarts(event: Event): void {
event.preventDefault();
localStorage.setItem('quickstartsDismissed', 'true');
this.firstStepsDismissed = true;
} }
} }

View File

@@ -1,19 +1,20 @@
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MatRippleModule } from '@angular/material/core';
import { MatIconModule } from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatTooltipModule } from '@angular/material/tooltip';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { HasRoleModule } from 'src/app/directives/has-role/has-role.module'; import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
import { AvatarModule } from 'src/app/modules/avatar/avatar.module'; import { AvatarModule } from 'src/app/modules/avatar/avatar.module';
import { CardModule } from 'src/app/modules/card/card.module'; import { CardModule } from 'src/app/modules/card/card.module';
import { OnboardingModule } from 'src/app/modules/onboarding/onboarding.module';
import { SharedModule } from 'src/app/modules/shared/shared.module'; import { SharedModule } from 'src/app/modules/shared/shared.module';
import { HomeRoutingModule } from './home-routing.module'; import { HomeRoutingModule } from './home-routing.module';
import { HomeComponent } from './home.component'; import { HomeComponent } from './home.component';
@NgModule({ @NgModule({
declarations: [HomeComponent], declarations: [HomeComponent],
imports: [ imports: [
@@ -24,9 +25,12 @@ import { HomeComponent } from './home.component';
MatButtonModule, MatButtonModule,
TranslateModule, TranslateModule,
AvatarModule, AvatarModule,
MatTooltipModule,
SharedModule, SharedModule,
MatProgressSpinnerModule, MatProgressSpinnerModule,
CardModule, CardModule,
MatRippleModule,
OnboardingModule,
], ],
}) })
export class HomeModule { } export class HomeModule { }

View File

@@ -23,18 +23,14 @@
<p class="step-title">{{'APP.OIDC.TITLEFIRST' | translate}}</p> <p class="step-title">{{'APP.OIDC.TITLEFIRST' | translate}}</p>
<cnsl-form-field appearance="outline" class="formfield"> <cnsl-form-field appearance="outline" class="formfield">
<cnsl-label>{{ 'APP.NAME' | translate }}</cnsl-label> <cnsl-label>{{ 'APP.NAME' | translate }}</cnsl-label>
<input cnslInput formControlName="name" /> <input cnslInput cdkFocusInitial formControlName="name" />
<span cnsl-error *ngIf="name?.errors?.required">{{'PROJECT.APP.NAMEREQUIRED' | translate}}</span> <span cnsl-error *ngIf="name?.errors?.required">{{'PROJECT.APP.NAMEREQUIRED' | translate}}</span>
</cnsl-form-field> </cnsl-form-field>
<p class="step-title">{{'APP.OIDC.TYPETITLE' | translate}}</p> <p class="step-title">{{'APP.OIDC.TYPETITLE' | translate}}</p>
<mat-radio-group color="primary" aria-labelledby="radio-group-label" class="radio-group"
formControlName="applicationType"> <app-type-radio [types]="oidcAppTypes" (selectedType)="changedAppType($event)"
<mat-radio-button class="radio-button" *ngFor="let type of oidcAppTypes | keyvalue" [selected]="applicationType?.value"></app-type-radio>
[value]="type.value">
<div>{{('APP.OIDC.APPTYPE'+type.key.toString()) | translate}}</div>
</mat-radio-button>
</mat-radio-group>
<div class="actions"> <div class="actions">
<button mat-raised-button [disabled]="firstFormGroup.invalid" color="primary" <button mat-raised-button [disabled]="firstFormGroup.invalid" color="primary"
matStepperNext>{{'ACTIONS.CONTINUE' | translate}}</button> matStepperNext>{{'ACTIONS.CONTINUE' | translate}}</button>
@@ -42,37 +38,19 @@
</form> </form>
</mat-step> </mat-step>
<mat-step [editable]="true" <!-- skip for native applications -->
*ngIf="oidcApp.applicationType === OIDCApplicationType.OIDCAPPLICATIONTYPE_USER_AGENT"> <mat-step *ngIf="oidcApp.applicationType !== OIDCApplicationType.OIDCAPPLICATIONTYPE_NATIVE"
<ng-template matStepLabel>{{'APP.OIDC.RESPONSESECTION' | translate}}</ng-template>
<div class="checkbox-container">
<mat-checkbox class="checkbox" *ngFor="let responsetype of oidcResponseTypes"
(change)="changeResponseType()" color="primary" [(ngModel)]="responsetype.checked"
[disabled]="responsetype.disabled">
{{'APP.OIDC.RESPONSE'+responsetype.type | translate}}
</mat-checkbox>
</div>
<div class="actions">
<button mat-stroked-button color="primary" matStepperPrevious>{{'ACTIONS.BACK' | translate}}</button>
<button mat-raised-button color="primary" matStepperNext>{{'ACTIONS.CONTINUE' | translate}}</button>
</div>
</mat-step>
<mat-step *ngIf="oidcApp.applicationType === OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB"
[stepControl]="secondFormGroup" [editable]="true"> [stepControl]="secondFormGroup" [editable]="true">
<form [formGroup]="secondFormGroup"> <form [formGroup]="secondFormGroup">
<ng-template matStepLabel>{{'APP.OIDC.AUTHMETHODSECTION' | translate}}</ng-template> <ng-template matStepLabel>{{'APP.OIDC.AUTHMETHODSECTION' | translate}}</ng-template>
<mat-radio-group color="primary" aria-labelledby="example-radio-group-label" class="radio-group" <app-auth-method-radio [authMethods]="authMethods" [selected]="authMethod?.value"
formControlName="authMethodType"> (selectedMethod)="changedAppAuthMethod($event)">
<mat-radio-button class="radio-button" *ngFor="let authmethod of oidcAuthMethodType" </app-auth-method-radio>
[disabled]="authmethod.disabled" [value]="authmethod.type">
{{'APP.OIDC.AUTHMETHOD'+authmethod.type | translate}}
</mat-radio-button>
</mat-radio-group>
<div class="actions"> <div class="actions">
<button mat-stroked-button color="primary" <button mat-stroked-button color="primary" matStepperPrevious>{{'ACTIONS.BACK' |
matStepperPrevious>{{'ACTIONS.BACK' | translate}}</button> translate}}</button>
<button mat-raised-button color="primary" [disabled]="secondFormGroup.invalid" <button mat-raised-button color="primary" [disabled]="secondFormGroup.invalid"
matStepperNext>{{'ACTIONS.CONTINUE' | translate}}</button> matStepperNext>{{'ACTIONS.CONTINUE' | translate}}</button>
</div> </div>
@@ -89,25 +67,10 @@
<p class="step-description" *ngIf="oidcApp.applicationType === OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB"> <p class="step-description" *ngIf="oidcApp.applicationType === OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB">
{{'APP.OIDC.REDIRECTDESCRIPTIONWEB' | translate}}</p> {{'APP.OIDC.REDIRECTDESCRIPTIONWEB' | translate}}</p>
<form class="chip-form" (ngSubmit)="addUri(redInput, 'REDIRECT')"> <cnsl-redirect-uris class="redirect-section" [canWrite]="true"
<cnsl-form-field appearance="outline" class="full-width"> (changedUris)="oidcApp.redirectUrisList = $event" [urisList]="oidcApp.redirectUrisList"
<cnsl-label>{{ 'APP.OIDC.REDIRECT' | translate }}</cnsl-label> title="{{ 'APP.OIDC.REDIRECT' | translate }}">
<input #redInput cnslInput placeholder="{{'APP.OIDC.COMMAORENTERSEPERATION' | translate}}" </cnsl-redirect-uris>
[formControl]="redirectControl">
</cnsl-form-field>
<button matTooltip="{{'ACTIONS.ADD' | translate}}" type="submit" mat-icon-button>
<mat-icon>add</mat-icon>
</button>
</form>
<mat-chip-list #chipRedirectList aria-label="uri selection">
<mat-chip #redInput class="chip" *ngFor="let uri of oidcApp.redirectUrisList" selected removable
[matTooltip]="!uri?.startsWith('https://') ? ('APP.OIDC.UNSECUREREDIRECT' | translate): ''"
[color]="!uri?.startsWith('https://') ? 'warn': 'white'" (removed)="removeUri(uri, 'REDIRECT')">
{{uri}} <mat-icon matChipRemove>cancel</mat-icon>
</mat-chip>
</mat-chip-list>
<p *ngIf="redirectControl.invalid" class="error">{{'APP.OIDC.REDIRECTNOTVALID' | translate}}</p>
<p class="step-title">{{'APP.OIDC.POSTREDIRECTTITLE' | translate}}</p> <p class="step-title">{{'APP.OIDC.POSTREDIRECTTITLE' | translate}}</p>
<p class="step-description" <p class="step-description"
@@ -117,26 +80,10 @@
*ngIf="oidcApp.applicationType === OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB || oidcApp.applicationType === OIDCApplicationType.OIDCAPPLICATIONTYPE_USER_AGENT"> *ngIf="oidcApp.applicationType === OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB || oidcApp.applicationType === OIDCApplicationType.OIDCAPPLICATIONTYPE_USER_AGENT">
{{'APP.OIDC.REDIRECTDESCRIPTIONWEB' | translate}}</p> {{'APP.OIDC.REDIRECTDESCRIPTIONWEB' | translate}}</p>
<form class="chip-form" (ngSubmit)="addUri(postInput, 'POSTREDIRECT')"> <cnsl-redirect-uris class="redirect-section" [canWrite]="true"
<cnsl-form-field appearance="outline" class="full-width"> (changedUris)="oidcApp.postLogoutRedirectUrisList = $event"
<cnsl-label>{{ 'APP.OIDC.POSTLOGOUTREDIRECT' | translate }}</cnsl-label> [urisList]="oidcApp.postLogoutRedirectUrisList" title="{{ 'APP.OIDC.POSTLOGOUTREDIRECT' | translate }}">
<input #postInput cnslInput placeholder="{{'APP.OIDC.COMMAORENTERSEPERATION' | translate}}" </cnsl-redirect-uris>
[formControl]="postRedirectControl">
</cnsl-form-field>
<button matTooltip="{{'ACTIONS.ADD' | translate}}" type="submit" mat-icon-button>
<mat-icon>add</mat-icon>
</button>
</form>
<mat-chip-list #chipPostRedirectList aria-label="uri selection">
<mat-chip class="chip" *ngFor="let uri of oidcApp.postLogoutRedirectUrisList"
[matTooltip]="!uri?.startsWith('https://') ? ('APP.OIDC.UNSECUREREDIRECT' | translate): ''"
removable (removed)="removeUri(uri, 'POSTREDIRECT')" selected
[color]="!uri?.startsWith('https://') ? 'warn': 'white'">
{{uri}} <mat-icon matChipRemove>cancel</mat-icon>
</mat-chip>
</mat-chip-list>
<p *ngIf="postRedirectControl.invalid" class="error">{{'APP.OIDC.REDIRECTNOTVALID' | translate}}</p>
<div class="actions"> <div class="actions">
<button mat-stroked-button color="primary" matStepperPrevious>{{'ACTIONS.BACK' | translate}}</button> <button mat-stroked-button color="primary" matStepperPrevious>{{'ACTIONS.BACK' | translate}}</button>
@@ -171,9 +118,8 @@
<span class="right" *ngIf="oidcApp.grantTypesList?.length > 0"> <span class="right" *ngIf="oidcApp.grantTypesList?.length > 0">
[<span *ngFor="let element of oidcApp.grantTypesList; index as i"> [<span *ngFor="let element of oidcApp.grantTypesList; index as i">
{{'APP.OIDC.GRANT'+element | translate}} {{'APP.OIDC.GRANT'+element | translate}}
{{i < oidcApp.grantTypesList.length - 1 ? ', ': ''}} {{i < oidcApp.grantTypesList.length - 1 ? ', ' : '' }} </span>]
</span>] </span>
</span>
</div> </div>
<div class="row"> <div class="row">
<span class="left"> <span class="left">
@@ -182,9 +128,8 @@
<span class="right" *ngIf="oidcApp.responseTypesList?.length > 0"> <span class="right" *ngIf="oidcApp.responseTypesList?.length > 0">
[<span *ngFor="let element of oidcApp.responseTypesList; index as i"> [<span *ngFor="let element of oidcApp.responseTypesList; index as i">
{{('APP.OIDC.RESPONSE'+element | translate)}} {{('APP.OIDC.RESPONSE'+element | translate)}}
{{i < oidcApp.responseTypesList.length - 1 ? ', ': ''}} {{i < oidcApp.responseTypesList.length - 1 ? ', ' : '' }} </span>]
</span>] </span>
</span>
</div> </div>
<div class="row"> <div class="row">
@@ -205,9 +150,8 @@
<span class="right" *ngIf="oidcApp.redirectUrisList?.length > 0"> <span class="right" *ngIf="oidcApp.redirectUrisList?.length > 0">
[<span *ngFor="let redirect of oidcApp.redirectUrisList; index as i"> [<span *ngFor="let redirect of oidcApp.redirectUrisList; index as i">
{{redirect}} {{redirect}}
{{i < oidcApp.redirectUrisList.length - 1 ? ', ': ''}} {{i < oidcApp.redirectUrisList.length - 1 ? ', ' : '' }} </span>]
</span>] </span>
</span>
</div> </div>
<div class="row"> <div class="row">
@@ -217,15 +161,14 @@
<span class="right" *ngIf="oidcApp.postLogoutRedirectUrisList?.length > 0"> <span class="right" *ngIf="oidcApp.postLogoutRedirectUrisList?.length > 0">
[<span *ngFor="let redirect of oidcApp.postLogoutRedirectUrisList; index as i"> [<span *ngFor="let redirect of oidcApp.postLogoutRedirectUrisList; index as i">
{{redirect}} {{redirect}}
{{i < oidcApp.postLogoutRedirectUrisList.length - 1 ? ', ': ''}} {{i < oidcApp.postLogoutRedirectUrisList.length - 1 ? ', ' : '' }} </span>]
</span>] </span>
</span>
</div> </div>
<div class="actions"> <div class="actions">
<button mat-stroked-button color="primary" matStepperPrevious>{{'ACTIONS.BACK' | translate}}</button> <button mat-stroked-button color="primary" matStepperPrevious>{{'ACTIONS.BACK' | translate}}</button>
<button mat-raised-button color="primary" <button mat-raised-button color="primary" (click)="saveOIDCApp()">{{'ACTIONS.CREATE' |
(click)="saveOIDCApp()">{{'ACTIONS.CREATE' | translate}}</button> translate}}</button>
</div> </div>
</mat-step> </mat-step>
</mat-horizontal-stepper> </mat-horizontal-stepper>
@@ -241,8 +184,8 @@
<cnsl-form-field appearance="outline" class="formfield"> <cnsl-form-field appearance="outline" class="formfield">
<cnsl-label>{{ 'APP.OIDC.APPTYPE' | translate }}</cnsl-label> <cnsl-label>{{ 'APP.OIDC.APPTYPE' | translate }}</cnsl-label>
<mat-select formControlName="applicationType"> <mat-select formControlName="applicationType">
<mat-option *ngFor="let type of oidcAppTypes" [value]="type"> <mat-option *ngFor="let type of oidcAppTypes" [value]="type.type">
{{ 'APP.OIDC.APPTYPE'+type | translate }} {{ 'APP.OIDC.APPTYPE'+type.type | translate }}
</mat-option> </mat-option>
</mat-select> </mat-select>
</cnsl-form-field> </cnsl-form-field>
@@ -274,32 +217,18 @@
</mat-select> </mat-select>
</cnsl-form-field> </cnsl-form-field>
<cnsl-form-field appearance="outline" class="formfield full-width"> <div class="formfield full-width">
<cnsl-label>{{ 'APP.OIDC.REDIRECT' | translate }}</cnsl-label> <cnsl-redirect-uris class="redirect-section" [canWrite]="true"
<mat-chip-list #chipRedirectList aria-label="uri selection"> (changedUris)="oidcApp.redirectUrisList = $event" [urisList]="oidcApp.redirectUrisList"
<mat-chip class="chip" *ngFor="let uri of oidcApp.redirectUrisList" removable title="{{ 'APP.OIDC.REDIRECT' | translate }}">
(removed)="removeUri(uri, 'REDIRECT')"> </cnsl-redirect-uris>
{{uri}} <mat-icon matChipRemove>cancel</mat-icon>
</mat-chip>
<input cnslInput [matChipInputFor]="chipRedirectList"
[matChipInputSeparatorKeyCodes]="separatorKeysCodes" [matChipInputAddOnBlur]="true"
(matChipInputTokenEnd)="addUri($event, 'REDIRECT')">
</mat-chip-list>
</cnsl-form-field>
<cnsl-form-field appearance="outline" class="formfield full-width">
<cnsl-label>{{ 'APP.OIDC.POSTLOGOUTREDIRECT' | translate }}</cnsl-label>
<mat-chip-list #chipPostRedirectList aria-label="uri selection">
<mat-chip class="chip" *ngFor="let uri of oidcApp.postLogoutRedirectUrisList" removable
(removed)="removeUri(uri, 'POSTREDIRECT')">
{{uri}} <mat-icon matChipRemove>cancel</mat-icon>
</mat-chip>
<input cnslInput [matChipInputFor]="chipPostRedirectList"
[matChipInputSeparatorKeyCodes]="separatorKeysCodes" [matChipInputAddOnBlur]="true"
(matChipInputTokenEnd)="addUri($event, 'POSTREDIRECT')">
</mat-chip-list>
</cnsl-form-field>
<cnsl-redirect-uris class="redirect-section" [canWrite]="true"
(changedUris)="oidcApp.postLogoutRedirectUrisList = $event"
[urisList]="oidcApp.postLogoutRedirectUrisList"
title="{{ 'APP.OIDC.POSTLOGOUTREDIRECT' | translate }}">
</cnsl-redirect-uris>
</div>
</div> </div>
<button color="primary" mat-raised-button class="continue-button" [disabled]="form.invalid" cdkFocusInitial <button color="primary" mat-raised-button class="continue-button" [disabled]="form.invalid" cdkFocusInitial

View File

@@ -42,11 +42,6 @@ p.desc {
margin-right: .5rem; margin-right: .5rem;
} }
.formfield {
width: 400px;
display: block;
}
.full-width { .full-width {
width: 100%; width: 100%;
} }
@@ -55,6 +50,10 @@ p.desc {
background: inherit !important; background: inherit !important;
margin: 0 -1.5rem; margin: 0 -1.5rem;
.formfield {
max-width: 400px;
}
.step-title { .step-title {
font-size: 1rem; font-size: 1rem;
text-transform: uppercase; text-transform: uppercase;
@@ -65,44 +64,6 @@ p.desc {
font-size: .9rem; font-size: .9rem;
color: var(--grey); color: var(--grey);
} }
.chip-form {
width: 100%;
display: flex;
align-items: center;
.formfield {
flex: 1;
}
button {
margin-top: 1rem;
}
}
.error {
font-size: 13px;
color: #f44336;
margin-top: 0;
}
.chip {
border-radius: 4px;
height: 40px;
}
.chip[color='white'] {
background-color: #fafafa;
}
}
.radio-group {
display: flex;
flex-direction: column;
.radio-button {
margin: .5rem 0;
}
} }
.checkbox-container { .checkbox-container {
@@ -137,7 +98,6 @@ p.desc {
float: right; float: right;
margin-top: 1rem; margin-top: 1rem;
border-radius: .5rem; border-radius: .5rem;
padding: .5rem 1rem;
min-width: 100px; min-width: 100px;
} }
} }
@@ -147,9 +107,11 @@ p.desc {
display: flex; display: flex;
margin: 0 -.5rem; margin: 0 -.5rem;
flex-wrap: wrap; flex-wrap: wrap;
flex-direction: row;
.formfield { .formfield {
flex: 1 0 40%; flex: 1;
box-sizing: border-box;
margin: 0 .5rem; margin: 0 .5rem;
&.full-width { &.full-width {
@@ -164,4 +126,4 @@ p.desc {
padding: .5rem 4rem; padding: .5rem 4rem;
float: right; float: right;
} }
} }

View File

@@ -6,6 +6,7 @@ import { MatDialog } from '@angular/material/dialog';
import { ActivatedRoute, Params, Router } from '@angular/router'; import { ActivatedRoute, Params, Router } from '@angular/router';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { debounceTime } from 'rxjs/operators'; import { debounceTime } from 'rxjs/operators';
import { RadioItemAuthType } from 'src/app/modules/app-radio/app-auth-method-radio/app-auth-method-radio.component';
import { import {
Application, Application,
OIDCApplicationCreate, OIDCApplicationCreate,
@@ -17,7 +18,15 @@ import {
import { ManagementService } from 'src/app/services/mgmt.service'; import { ManagementService } from 'src/app/services/mgmt.service';
import { ToastService } from 'src/app/services/toast.service'; import { ToastService } from 'src/app/services/toast.service';
import {
WEB_TYPE,
NATIVE_TYPE,
USER_AGENT_TYPE
} from '../authtypes';
import { AppSecretDialogComponent } from '../app-secret-dialog/app-secret-dialog.component'; import { AppSecretDialogComponent } from '../app-secret-dialog/app-secret-dialog.component';
import { CODE_METHOD, getPartialConfigFromAuthMethod, IMPLICIT_METHOD, PKCE_METHOD, PK_JWT_METHOD, POST_METHOD } from '../authmethods';
@Component({ @Component({
selector: 'app-app-create', selector: 'app-app-create',
@@ -37,10 +46,16 @@ export class AppCreateComponent implements OnInit, OnDestroy {
{ type: OIDCResponseType.OIDCRESPONSETYPE_ID_TOKEN_TOKEN, checked: false, disabled: false }, { type: OIDCResponseType.OIDCRESPONSETYPE_ID_TOKEN_TOKEN, checked: false, disabled: false },
]; ];
public oidcAppTypes: OIDCApplicationType[] = [ public oidcAppTypes: any = [
OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB, WEB_TYPE,
OIDCApplicationType.OIDCAPPLICATIONTYPE_USER_AGENT, NATIVE_TYPE,
OIDCApplicationType.OIDCAPPLICATIONTYPE_NATIVE, USER_AGENT_TYPE,
];
public authMethods: RadioItemAuthType[] = [
PKCE_METHOD,
CODE_METHOD,
POST_METHOD,
]; ];
public oidcAuthMethodType: { type: OIDCAuthMethodType, checked: boolean, disabled: boolean; }[] = [ public oidcAuthMethodType: { type: OIDCAuthMethodType, checked: boolean, disabled: boolean; }[] = [
@@ -52,7 +67,6 @@ export class AppCreateComponent implements OnInit, OnDestroy {
// stepper // stepper
firstFormGroup!: FormGroup; firstFormGroup!: FormGroup;
secondFormGroup!: FormGroup; secondFormGroup!: FormGroup;
// thirdFormGroup!: FormGroup;
// devmode // devmode
public form!: FormGroup; public form!: FormGroup;
@@ -72,9 +86,6 @@ export class AppCreateComponent implements OnInit, OnDestroy {
// TODO show when implemented // TODO show when implemented
]; ];
public redirectControl: FormControl = new FormControl('');
public postRedirectControl: FormControl = new FormControl('');
public readonly separatorKeysCodes: number[] = [ENTER, COMMA, SPACE]; public readonly separatorKeysCodes: number[] = [ENTER, COMMA, SPACE];
constructor( constructor(
@@ -104,64 +115,58 @@ export class AppCreateComponent implements OnInit, OnDestroy {
this.firstFormGroup = this.fb.group({ this.firstFormGroup = this.fb.group({
name: ['', [Validators.required]], name: ['', [Validators.required]],
applicationType: ['', [Validators.required]], applicationType: [OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB, [Validators.required]],
}); });
this.firstFormGroup.valueChanges.subscribe(value => { this.firstFormGroup.valueChanges.subscribe(value => {
if (this.firstFormGroup.valid) { if (this.firstFormGroup.valid) {
switch (value.applicationType) {
case OIDCApplicationType.OIDCAPPLICATIONTYPE_NATIVE:
this.oidcResponseTypes[0].checked = true;
this.oidcApp.responseTypesList = [OIDCResponseType.OIDCRESPONSETYPE_CODE];
this.oidcApp.grantTypesList =
[OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE];
this.oidcApp.authMethodType = OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE;
// this.redirectControl = new FormControl('', [nativeValidator as ValidatorFn]);
// this.postRedirectControl = new FormControl('', [nativeValidator as ValidatorFn]);
break;
case OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB:
this.oidcAuthMethodType[0].disabled = false;
this.oidcAuthMethodType[1].disabled = false;
this.oidcAuthMethodType[2].disabled = false;
this.authMethodType?.setValue(OIDCAuthMethodType.OIDCAUTHMETHODTYPE_BASIC);
this.oidcApp.authMethodType = OIDCAuthMethodType.OIDCAUTHMETHODTYPE_BASIC;
this.oidcResponseTypes[0].checked = true;
this.oidcApp.responseTypesList = [OIDCResponseType.OIDCRESPONSETYPE_CODE];
this.changeResponseType();
this.oidcApp.grantTypesList =
[OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE];
// this.redirectControl = new FormControl('', [webValidator as ValidatorFn]);
// this.postRedirectControl = new FormControl('', [webValidator as ValidatorFn]);
break;
case OIDCApplicationType.OIDCAPPLICATIONTYPE_USER_AGENT:
this.oidcResponseTypes[0].checked = true;
this.oidcApp.responseTypesList = [OIDCResponseType.OIDCRESPONSETYPE_CODE];
this.oidcApp.grantTypesList =
[OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE, OIDCGrantType.OIDCGRANTTYPE_IMPLICIT];
this.oidcApp.authMethodType = OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE;
// this.redirectControl = new FormControl('', [webValidator as ValidatorFn]);
// this.postRedirectControl = new FormControl('', [webValidator as ValidatorFn]);
break;
}
this.oidcApp.name = this.name?.value; this.oidcApp.name = this.name?.value;
this.oidcApp.applicationType = this.applicationType?.value; this.oidcApp.applicationType = this.applicationType?.value;
switch (this.applicationType?.value) {
case OIDCApplicationType.OIDCAPPLICATIONTYPE_NATIVE:
this.authMethods = [
PKCE_METHOD,
];
// automatically set to PKCE and skip step
this.oidcApp.responseTypesList = [OIDCResponseType.OIDCRESPONSETYPE_CODE];
this.oidcApp.grantTypesList = [OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE];
this.oidcApp.authMethodType = OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE;
break;
case OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB:
this.authMethods = [
PKCE_METHOD,
CODE_METHOD,
POST_METHOD,
];
this.authMethod?.setValue(PKCE_METHOD.key);
break;
case OIDCApplicationType.OIDCAPPLICATIONTYPE_USER_AGENT:
this.authMethods = [
PKCE_METHOD,
IMPLICIT_METHOD,
];
this.authMethod?.setValue(PKCE_METHOD.key);
break;
}
} }
}); });
this.secondFormGroup = this.fb.group({ this.secondFormGroup = this.fb.group({
authMethodType: [OIDCAuthMethodType.OIDCAUTHMETHODTYPE_BASIC, [Validators.required]], authMethod: [this.authMethods[0].key, [Validators.required]],
}); });
this.secondFormGroup.valueChanges.subscribe(value => { this.secondFormGroup.valueChanges.subscribe(form => {
this.oidcApp.authMethodType = value.authMethodType; const partialConfig = getPartialConfigFromAuthMethod(form.authMethod);
if (partialConfig) {
this.oidcApp.responseTypesList = partialConfig.responseTypesList ?? [];
this.oidcApp.grantTypesList = partialConfig.grantTypesList ?? [];
this.oidcApp.authMethodType = partialConfig.authMethodType ?? OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE;
}
}); });
} }
@@ -173,6 +178,15 @@ export class AppCreateComponent implements OnInit, OnDestroy {
this.subscription?.unsubscribe(); this.subscription?.unsubscribe();
} }
public changedAppType(type: OIDCApplicationType) {
this.firstFormGroup.controls['applicationType'].setValue(type);
}
public changedAppAuthMethod(methodKey: string) {
console.log(methodKey);
this.secondFormGroup.controls['authMethod'].setValue(methodKey);
}
private async getData({ projectid }: Params): Promise<void> { private async getData({ projectid }: Params): Promise<void> {
this.projectId = projectid; this.projectId = projectid;
this.oidcApp.projectId = projectid; this.oidcApp.projectId = projectid;
@@ -215,66 +229,20 @@ export class AppCreateComponent implements OnInit, OnDestroy {
} }
} }
public addUri(input: any, target: string): void {
const value = input.value.trim();
if (value !== '') {
if (target === 'REDIRECT' && this.redirectControl.valid) {
this.oidcApp.redirectUrisList.push(value);
if (input) {
input.value = '';
}
} else if (target === 'POSTREDIRECT' && this.redirectControl.valid) {
this.oidcApp.postLogoutRedirectUrisList.push(value);
if (input) {
input.value = '';
}
}
}
}
public removeUri(uri: string, target: string): void {
if (target === 'REDIRECT') {
const index = this.oidcApp.redirectUrisList.indexOf(uri);
if (index !== undefined && index >= 0) {
this.oidcApp.redirectUrisList.splice(index, 1);
}
} else if (target === 'POSTREDIRECT') {
const index = this.oidcApp.postLogoutRedirectUrisList.indexOf(uri);
if (index !== undefined && index >= 0) {
this.oidcApp.postLogoutRedirectUrisList.splice(index, 1);
}
}
}
changeResponseType(): void {
this.oidcApp.responseTypesList = this.oidcResponseTypes.filter(gt => gt.checked).map(gt => gt.type);
}
moreThanOneOption(options: Array<{ type: OIDCGrantType, checked: boolean, disabled: boolean; }>): boolean {
return options.filter(option => option.disabled === false).length > 1;
}
get name(): AbstractControl | null { get name(): AbstractControl | null {
return this.firstFormGroup.get('name'); return this.firstFormGroup.get('name');
} }
get applicationType(): AbstractControl | null { get applicationType(): AbstractControl | null {
return this.firstFormGroup.get('applicationType'); return this.firstFormGroup.get('applicationType');
} }
public grantTypeChecked(type: OIDCGrantType): boolean { public grantTypeChecked(type: OIDCGrantType): boolean {
return this.oidcGrantTypes.filter(gt => gt.checked).map(gt => gt.type).findIndex(t => t === type) > -1; return this.oidcGrantTypes.filter(gt => gt.checked).map(gt => gt.type).findIndex(t => t === type) > -1;
} }
get responseTypesList(): AbstractControl | null { get responseTypesList(): AbstractControl | null {
return this.secondFormGroup.get('responseTypesList'); return this.secondFormGroup.get('responseTypesList');
} }
get authMethod(): AbstractControl | null {
get authMethodType(): AbstractControl | null { return this.secondFormGroup.get('authMethod');
return this.secondFormGroup.get('authMethodType');
} }
// devmode // devmode
@@ -282,24 +250,17 @@ export class AppCreateComponent implements OnInit, OnDestroy {
get formname(): AbstractControl | null { get formname(): AbstractControl | null {
return this.form.get('name'); return this.form.get('name');
} }
get formresponseTypesList(): AbstractControl | null { get formresponseTypesList(): AbstractControl | null {
return this.form.get('responseTypesList'); return this.form.get('responseTypesList');
} }
get formgrantTypesList(): AbstractControl | null { get formgrantTypesList(): AbstractControl | null {
return this.form.get('grantTypesList'); return this.form.get('grantTypesList');
} }
get formapplicationType(): AbstractControl | null { get formapplicationType(): AbstractControl | null {
return this.form.get('applicationType'); return this.form.get('applicationType');
} }
get formauthMethodType(): AbstractControl | null { get formauthMethodType(): AbstractControl | null {
return this.form.get('authMethodType'); return this.form.get('authMethodType');
} }
} };

View File

@@ -1,10 +1,32 @@
<app-meta-layout> <app-meta-layout>
<div class="max-width-container"> <div class="enlarged-container">
<div class="head"> <div class="head">
<a [routerLink]="['/projects', projectId]" mat-icon-button> <a [routerLink]="['/projects', projectId]" mat-icon-button>
<mat-icon class="icon">arrow_back</mat-icon> <mat-icon class="icon">arrow_back</mat-icon>
</a> </a>
<h1>{{ 'APP.PAGES.TITLE' | translate }} {{app?.name}}</h1> <div class="title-col">
<h1>{{app?.name}}</h1>
<span>{{'APP.OIDC.APPTYPE'+app?.oidcConfig?.applicationType | translate}}</span>
</div>
<ng-container *ngIf="isZitadel === false">
<ng-template appHasRole [appHasRole]="['project.app.write:'+projectId, 'project.app.write']">
<button *ngIf="!editState" matTooltip="{{'ACTIONS.EDIT' | translate}}" mat-icon-button
(click)="editState = !editState" aria-label="edit app name">
<i class="las la-edit"></i>
</button>
<button *ngIf="editState" (click)="saveApp()" [disabled]="appNameForm.invalid || name?.disabled"
mat-icon-button>
<i class="las la-save"></i>
</button>
</ng-template>
<ng-template appHasRole [appHasRole]="['project.app.delete:'+projectId, 'project.app.delete']">
<button matTooltip="{{'ACTIONS.DELETE' | translate}}" color="warn" mat-icon-button
(click)="deleteApp()" aria-label="delete app">
<i class="las la-trash"></i>
</button>
</ng-template>
</ng-container>
<p class="desc">{{ 'APP.PAGES.DESCRIPTION' | translate }}</p> <p class="desc">{{ 'APP.PAGES.DESCRIPTION' | translate }}</p>
<p *ngIf="isZitadel" class="zitadel-warning">{{'PROJECT.PAGES.ZITADELPROJECT' | translate}}</p> <p *ngIf="isZitadel" class="zitadel-warning">{{'PROJECT.PAGES.ZITADELPROJECT' | translate}}</p>
@@ -12,52 +34,85 @@
<span *ngIf="errorMessage" class="err-container">{{errorMessage}}</span> <span *ngIf="errorMessage" class="err-container">{{errorMessage}}</span>
<app-card title="{{ 'APP.PAGES.DETAIL.TITLE' | translate }}" *ngIf="app"> <form *ngIf="app && editState" [formGroup]="appNameForm">
<form [formGroup]="appNameForm" (ngSubmit)="saveApp()"> <div class="name-content">
<div class="name-content"> <mat-button-toggle-group formControlName="state" class="toggle" (change)="changeState($event)">
<mat-button-toggle-group formControlName="state" class="toggle" (change)="changeState($event)"> <mat-button-toggle [value]="AppState.APPSTATE_INACTIVE"
<mat-button-toggle [value]="AppState.APPSTATE_INACTIVE" matTooltip="{{ 'ACTIONS.DEACTIVATE' | translate}}">
matTooltip="{{ 'ACTIONS.DEACTIVATE' | translate}}"> {{'APP.PAGES.DETAIL.STATE.'+AppState.APPSTATE_INACTIVE | translate}}
{{'APP.PAGES.DETAIL.STATE.'+AppState.APPSTATE_INACTIVE | translate}} </mat-button-toggle>
</mat-button-toggle> <mat-button-toggle [value]="AppState.APPSTATE_ACTIVE"
<mat-button-toggle [value]="AppState.APPSTATE_ACTIVE" matTooltip="{{ 'ACTIONS.REACTIVATE' | translate}}">
matTooltip="{{ 'ACTIONS.REACTIVATE' | translate}}"> {{'APP.PAGES.DETAIL.STATE.'+AppState.APPSTATE_ACTIVE | translate}}
{{'APP.PAGES.DETAIL.STATE.'+AppState.APPSTATE_ACTIVE | translate}} </mat-button-toggle>
</mat-button-toggle> </mat-button-toggle-group>
</mat-button-toggle-group>
<cnsl-form-field class="name-field"> <cnsl-form-field class="name-field">
<cnsl-label>{{ 'APP.NAME' | translate }}</cnsl-label> <cnsl-label>{{ 'APP.NAME' | translate }}</cnsl-label>
<input cnslInput formControlName="name" /> <input cnslInput formControlName="name" />
</cnsl-form-field> </cnsl-form-field>
<cnsl-info-section class="docs-line" *ngIf="docs?.discoveryEndpoint">
<p><strong>Discovery Endpoint:</strong> {{docs.discoveryEndpoint}}</p>
<p><strong>Issuer:</strong> {{docs.issuer}}</p>
</cnsl-info-section>
</div>
<div class="btn-container">
<button type="submit" color="primary" [disabled]="appNameForm.invalid || name?.disabled"
mat-raised-button>{{ 'ACTIONS.SAVE' | translate }}</button>
</div>
</form>
</app-card>
<app-card title="{{ 'APP.OIDC.TITLE' | translate }}" *ngIf="app && app.oidcConfig">
<div card-actions *ngIf="app?.oidcConfig?.authMethodType !== OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE">
<button [disabled]="!canWrite" mat-stroked-button
(click)="regenerateOIDCClientSecret()">{{'APP.OIDC.REGENERATESECRET' | translate}}</button>
</div> </div>
</form>
<!-- <cnsl-info-section class="docs-line" *ngIf="docs?.discoveryEndpoint">
<p><strong>Discovery Endpoint:</strong> {{docs.discoveryEndpoint}}</p>
<p><strong>Issuer:</strong> {{docs.issuer}}</p>
</cnsl-info-section> -->
<div class="compliance"
*ngIf="app?.oidcConfig?.complianceProblemsList && app.oidcConfig?.complianceProblemsList?.length">
<cnsl-info-section class="problem" type="WARN">
<ul style="margin: 0;">
<li style="margin: 0 0 .5rem 0;"
*ngFor="let problem of app.oidcConfig?.complianceProblemsList || []">
{{problem.localizedMessage}}</li>
</ul>
</cnsl-info-section>
</div>
<div class="content">
<h3 class="full-width section-title">{{'APP.OIDC.REDIRECTSECTIONTITLE' | translate}}</h3>
<mat-slide-toggle color="primary" class="devmode" [formControl]="devMode" name="devMode"
matTooltip="{{'APP.OIDC.DEVMODEDESC' | translate}}">
{{ 'APP.OIDC.DEVMODE' | translate }}
</mat-slide-toggle>
<cnsl-info-section class="step-description"
*ngIf="applicationType?.value == OIDCApplicationType.OIDCAPPLICATIONTYPE_NATIVE">
<span>{{'APP.OIDC.REDIRECTDESCRIPTIONNATIVE' | translate}}</span>
</cnsl-info-section>
<p class="step-description"
*ngIf="applicationType?.value == OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB || applicationType?.value == OIDCApplicationType.OIDCAPPLICATIONTYPE_USER_AGENT">
{{'APP.OIDC.REDIRECTDESCRIPTIONWEB' | translate}}</p>
<div style="margin: .5rem" class="divider"></div>
<cnsl-redirect-uris class="redirect-section" [canWrite]="canWrite" [devMode]="devMode?.value"
(changedUris)="redirectUrisList = $event" [urisList]="redirectUrisList"
title="{{ 'APP.OIDC.REDIRECT' | translate }}">
</cnsl-redirect-uris>
<cnsl-redirect-uris class="redirect-section" [canWrite]="canWrite" [devMode]="devMode?.value"
(changedUris)="postLogoutRedirectUrisList = $event" [urisList]="postLogoutRedirectUrisList"
title="{{ 'APP.OIDC.POSTLOGOUTREDIRECT' | translate }}">
</cnsl-redirect-uris>
</div>
<app-auth-method-radio *ngIf="authMethods && initialAuthMethod && app?.oidcConfig" [authMethods]="authMethods"
[selected]="initialAuthMethod" [current]="currentAuthMethod"
(selectedMethod)="setPartialConfigFromAuthMethod($event)">
</app-auth-method-radio>
<form *ngIf="appForm" [formGroup]="appForm" (ngSubmit)="saveOIDCApp()">
<app-card title=" {{ 'APP.OIDC.TITLE' | translate }}" *ngIf="app && app.oidcConfig" [expanded]="false">
<div card-actions
*ngIf="app?.oidcConfig?.authMethodType !== OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE">
<button [disabled]="!canWrite" mat-stroked-button
(click)="regenerateOIDCClientSecret()">{{'APP.OIDC.REGENERATESECRET' | translate}}</button>
</div>
<div class="compliance">
<cnsl-info-section class="problem">
<ul style="margin: 0;">
<li style="margin: 0 0 .5rem 0;" *ngFor="let problem of app.oidcConfig.complianceProblemsList">
{{problem.localizedMessage}}</li>
</ul>
</cnsl-info-section>
</div>
<form *ngIf="appForm" [formGroup]="appForm" (ngSubmit)="saveOIDCApp()">
<div class="content"> <div class="content">
<cnsl-form-field class="formfield" appearance="outline"> <cnsl-form-field class="formfield" appearance="outline">
<cnsl-label>{{ 'APP.OIDC.CLIENTID' | translate }}</cnsl-label> <cnsl-label>{{ 'APP.OIDC.CLIENTID' | translate }}</cnsl-label>
@@ -141,89 +196,46 @@
<cnsl-info-section class="full-width desc"> <cnsl-info-section class="full-width desc">
<span>{{'APP.OIDC.CLOCKSKEW' | translate}}</span> <span>{{'APP.OIDC.CLOCKSKEW' | translate}}</span>
</cnsl-info-section> </cnsl-info-section>
<div class="divider"></div>
<p class="full-width section-title">{{'APP.OIDC.REDIRECTSECTIONTITLE' | translate}}</p>
<mat-slide-toggle color="primary" class="devmode" formControlName="devMode" name="devMode">
{{ 'APP.OIDC.DEVMODE' | translate }}
</mat-slide-toggle>
<cnsl-info-section class="step-description">
<span style="margin-bottom: 2rem;">{{'APP.OIDC.DEVMODEDESC' | translate}}</span>
</cnsl-info-section>
<cnsl-info-section class="step-description"
*ngIf="applicationType?.value == OIDCApplicationType.OIDCAPPLICATIONTYPE_NATIVE">
<span>{{'APP.OIDC.REDIRECTDESCRIPTIONNATIVE' | translate}}</span>
</cnsl-info-section>
<p class="step-description"
*ngIf="applicationType?.value == OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB || applicationType?.value == OIDCApplicationType.OIDCAPPLICATIONTYPE_USER_AGENT">
{{'APP.OIDC.REDIRECTDESCRIPTIONWEB' | translate}}</p>
<form class="chip-form" (ngSubmit)="add(redInput, RedirectType.REDIRECT)">
<cnsl-form-field class="formfield full-width">
<cnsl-label>{{ 'APP.OIDC.REDIRECT' | translate }}</cnsl-label>
<input #redInput cnslInput placeholder="{{'APP.OIDC.COMMAORENTERSEPERATION' | translate}}"
[formControl]="redirectControl">
</cnsl-form-field>
<button matTooltip="{{'ACTIONS.ADD' | translate}}" type="submit" mat-icon-button
[disabled]="redirectControl.invalid || !canWrite">
<mat-icon>add</mat-icon>
</button>
</form>
<mat-chip-list class="chiplist formfield full-width" [disabled]="!canWrite" #chipRedirectList>
<mat-chip class="chip" *ngFor="let redirect of redirectUrisList" selected
[matTooltip]="!redirect?.startsWith('https://') ? ('APP.OIDC.UNSECUREREDIRECT' | translate): ''"
[color]="!redirect?.startsWith('https://') ? 'warn': 'green'"
(removed)="remove(redirect, RedirectType.REDIRECT)">
{{redirect}}
<mat-icon matChipRemove *ngIf="removable">cancel</mat-icon>
</mat-chip>
</mat-chip-list>
<p *ngIf="redirectControl.value && redirectControl.invalid" class="error">
{{'APP.OIDC.REDIRECTNOTVALID' | translate}}</p>
<form class="chip-form" (ngSubmit)="add(postInput, RedirectType.POSTREDIRECT)">
<cnsl-form-field class="formfield full-width">
<cnsl-label>{{ 'APP.OIDC.POSTLOGOUTREDIRECT' | translate }}</cnsl-label>
<input #postInput cnslInput placeholder="{{'APP.OIDC.COMMAORENTERSEPERATION' | translate}}"
[formControl]="postRedirectControl">
</cnsl-form-field>
<button matTooltip="{{'ACTIONS.ADD' | translate}}" type="submit" mat-icon-button
[disabled]="postRedirectControl.invalid || !canWrite">
<mat-icon>add</mat-icon>
</button>
</form>
<mat-chip-list class="chiplist formfield full-width" [disabled]="!canWrite" #chipPostRedirectList>
<mat-chip class="chip" *ngFor="let redirect of postLogoutRedirectUrisList" selected
(removed)="remove(redirect, RedirectType.POSTREDIRECT)"
[matTooltip]="!redirect?.startsWith('https://') ? ('APP.OIDC.UNSECUREREDIRECT' | translate): ''"
[color]="!redirect?.startsWith('https://') ? 'warn': 'green'">
{{redirect}}
<mat-icon matChipRemove *ngIf="removable">cancel</mat-icon>
</mat-chip>
</mat-chip-list>
<p *ngIf="postRedirectControl.value && postRedirectControl.invalid" class="error">
{{'APP.OIDC.REDIRECTNOTVALID' | translate}}</p>
</div> </div>
<div class="btn-container"> </app-card>
<button class="submit-button" type="submit" color="primary" <div class="btn-container">
[disabled]="appForm.invalid || !canWrite" <button class="submit-button" type="submit" color="primary" [disabled]="appForm.invalid || !canWrite"
mat-raised-button>{{ 'ACTIONS.SAVE' | translate }}</button> mat-raised-button>
{{ 'ACTIONS.SAVE' | translate }}
</button>
</div>
</form>
<div class="next-steps">
<h5>{{'APP.PAGES.NEXTSTEPS.TITLE' | translate}}</h5>
<div class="row">
<div class="step">
<h6>{{ 'APP.PAGES.NEXTSTEPS.0.TITLE' | translate }}</h6>
<p>{{'APP.PAGES.NEXTSTEPS.0.DESC' | translate}}</p>
<span class="fill-space"></span>
<a [routerLink]="['/projects', this.projectId]" color="primary" mat-mini-fab><i
class="las la-angle-right"></i></a>
</div> </div>
</form> <div class="step">
<h6>{{ 'APP.PAGES.NEXTSTEPS.1.TITLE' | translate }}</h6>
</app-card> <p>{{'APP.PAGES.NEXTSTEPS.1.DESC' | translate}}</p>
<span class="fill-space"></span>
<a [routerLink]="['/users', 'create']" color="primary" mat-mini-fab><i
class="las la-angle-right"></i></a>
</div>
<div class="step">
<h6>{{ 'APP.PAGES.NEXTSTEPS.2.TITLE' | translate }}</h6>
<p>{{'APP.PAGES.NEXTSTEPS.2.DESC' | translate}}</p>
<span class="fill-space"></span>
<a href="https://docs.zitadel.ch" color="primary" mat-mini-fab><i
class="las la-angle-right"></i></a>
</div>
</div>
</div>
</div> </div>
<div class="side" metainfo> <div class="side" metainfo>
<div class="meta-details"> <div class="meta-details">
<div class="meta-row"> <div class="meta-row">

View File

@@ -8,11 +8,21 @@
display: block; display: block;
} }
h1 { .title-col {
font-size: 1.2rem;
margin: 0 1rem;
margin-left: 2rem; margin-left: 2rem;
font-weight: normal; margin-right: 1rem;
min-width: 200px;
h1 {
font-size: 1.2rem;
margin: 0 0 0 0;
font-weight: normal;
}
span {
font-size: 12px;
color: var(--grey);
}
} }
.desc { .desc {
@@ -20,6 +30,7 @@
display: block; display: block;
font-size: .9rem; font-size: .9rem;
color: var(--grey); color: var(--grey);
margin-top: 1.5rem;
} }
.zitadel-warning { .zitadel-warning {
@@ -41,10 +52,10 @@
display: flex; display: flex;
flex-direction: row; flex-direction: row;
flex-wrap: wrap; flex-wrap: wrap;
align-items: center;
.toggle { .toggle {
outline: none; outline: none;
align-self: flex-start;
margin-top: 1rem; margin-top: 1rem;
margin-right: 1rem; margin-right: 1rem;
border-radius: .5rem; border-radius: .5rem;
@@ -91,6 +102,11 @@
align-items: center; align-items: center;
} }
.redirect-section {
flex: 1;
margin: 0 .5rem;
}
.formfield { .formfield {
flex: 1 1 30%; flex: 1 1 30%;
margin: 0 .5rem; margin: 0 .5rem;
@@ -99,27 +115,9 @@
flex-basis: 100%; flex-basis: 100%;
} }
} }
.chiplist {
margin-bottom: 1rem;
}
.chip-form {
width: 100%;
display: flex;
align-items: center;
.formfield {
flex: 1;
}
button {
margin-top: 1rem;
}
}
.section-title { .section-title {
margin-bottom: 1.5rem; margin: 1.5rem 0 0 0;
} }
.full-width { .full-width {
@@ -142,7 +140,7 @@
.desc { .desc {
color: var(--grey); color: var(--grey);
font-size: 14px; font-size: 14px;
margin-bottom: 1rem; margin-bottom: 1.5rem;
} }
.devmode { .devmode {
@@ -170,18 +168,67 @@
margin-top: 1rem; margin-top: 1rem;
} }
.chip {
border-radius: 4px;
height: 40px;
}
.chip[color='green'] {
background-color: #56a392 !important;
}
.divider { .divider {
flex-basis: 100%; flex-basis: 100%;
margin: 1.5rem .5rem; margin: 1.5rem .5rem;
height: 1px; height: 1px;
background-color: rgba(#8795a1, .2); background-color: rgba(#8795a1, .2);
} }
.next-steps {
h5 {
text-transform: uppercase;
font-size: 14px;
color: var(--grey);
}
.row {
width: 100%;
display: flex;
overflow-x: auto;
.step {
min-width: 220px;
max-width: 280px;
padding: 1rem;
margin: 0 .5rem;
border: 1px solid var(--grey);
border-radius: .5rem;
display: flex;
flex-direction: column;
align-items: center;
box-sizing: border-box;
flex: 1;
h6 {
font-size: 1rem;
text-align: center;
margin: 0 0 1rem 0;
}
p {
font-size: 14px;
text-align: center;
color: var(--grey);
}
.fill-space {
flex: 1;
}
button {
display: block;
margin: auto;
}
&:first-child {
margin-left: 0;
}
&:last-child {
margin-right: 0;
}
}
}
}

View File

@@ -4,12 +4,14 @@ import { Component, OnDestroy, OnInit } from '@angular/core';
import { AbstractControl, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; import { AbstractControl, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
import { MatButtonToggleChange } from '@angular/material/button-toggle'; import { MatButtonToggleChange } from '@angular/material/button-toggle';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
import { ActivatedRoute, Params } from '@angular/router'; import { ActivatedRoute, Params, Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { Duration } from 'google-protobuf/google/protobuf/duration_pb'; import { Duration } from 'google-protobuf/google/protobuf/duration_pb';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { take } from 'rxjs/operators'; import { take } from 'rxjs/operators';
import { RadioItemAuthType } from 'src/app/modules/app-radio/app-auth-method-radio/app-auth-method-radio.component';
import { ChangeType } from 'src/app/modules/changes/changes.component'; import { ChangeType } from 'src/app/modules/changes/changes.component';
import { WarnDialogComponent } from 'src/app/modules/warn-dialog/warn-dialog.component';
import { import {
Application, Application,
AppState, AppState,
@@ -27,11 +29,7 @@ import { ManagementService } from 'src/app/services/mgmt.service';
import { ToastService } from 'src/app/services/toast.service'; import { ToastService } from 'src/app/services/toast.service';
import { AppSecretDialogComponent } from '../app-secret-dialog/app-secret-dialog.component'; import { AppSecretDialogComponent } from '../app-secret-dialog/app-secret-dialog.component';
import { CODE_METHOD, getAuthMethodFromPartialConfig, getPartialConfigFromAuthMethod, IMPLICIT_METHOD, PKCE_METHOD, PK_JWT_METHOD, POST_METHOD, CUSTOM_METHOD } from '../authmethods';
enum RedirectType {
REDIRECT = 'redirect',
POSTREDIRECT = 'postredirect',
}
@Component({ @Component({
selector: 'app-app-detail', selector: 'app-app-detail',
@@ -39,12 +37,20 @@ enum RedirectType {
styleUrls: ['./app-detail.component.scss'], styleUrls: ['./app-detail.component.scss'],
}) })
export class AppDetailComponent implements OnInit, OnDestroy { export class AppDetailComponent implements OnInit, OnDestroy {
public editState: boolean = false;
public currentAuthMethod: string = CUSTOM_METHOD.key;
public initialAuthMethod: string = CUSTOM_METHOD.key;
public canWrite: boolean = false; public canWrite: boolean = false;
public errorMessage: string = ''; public errorMessage: string = '';
public removable: boolean = true; public removable: boolean = true;
public addOnBlur: boolean = true; public addOnBlur: boolean = true;
public readonly separatorKeysCodes: number[] = [ENTER, COMMA, SPACE]; public readonly separatorKeysCodes: number[] = [ENTER, COMMA, SPACE];
public authMethods: RadioItemAuthType[] = [
PKCE_METHOD,
CODE_METHOD,
POST_METHOD,
];
private subscription?: Subscription; private subscription?: Subscription;
public projectId: string = ''; public projectId: string = '';
public app!: Application.AsObject; public app!: Application.AsObject;
@@ -78,11 +84,10 @@ export class AppDetailComponent implements OnInit, OnDestroy {
public AppState: any = AppState; public AppState: any = AppState;
public appNameForm!: FormGroup; public appNameForm!: FormGroup;
public appForm!: FormGroup; public appForm!: FormGroup;
public redirectUrisList: string[] = []; public redirectUrisList: string[] = [];
public postLogoutRedirectUrisList: string[] = []; public postLogoutRedirectUrisList: string[] = [];
public RedirectType: any = RedirectType;
public isZitadel: boolean = false; public isZitadel: boolean = false;
public docs!: ZitadelDocs.AsObject; public docs!: ZitadelDocs.AsObject;
@@ -90,9 +95,6 @@ export class AppDetailComponent implements OnInit, OnDestroy {
public OIDCAuthMethodType: any = OIDCAuthMethodType; public OIDCAuthMethodType: any = OIDCAuthMethodType;
public OIDCTokenType: any = OIDCTokenType; public OIDCTokenType: any = OIDCTokenType;
public redirectControl: FormControl = new FormControl({ value: '', disabled: true });
public postRedirectControl: FormControl = new FormControl({ value: '', disabled: true });
public ChangeType: any = ChangeType; public ChangeType: any = ChangeType;
constructor( constructor(
public translate: TranslateService, public translate: TranslateService,
@@ -103,6 +105,7 @@ export class AppDetailComponent implements OnInit, OnDestroy {
private dialog: MatDialog, private dialog: MatDialog,
private mgmtService: ManagementService, private mgmtService: ManagementService,
private authService: GrpcAuthService, private authService: GrpcAuthService,
private router: Router,
) { ) {
this.appNameForm = this.fb.group({ this.appNameForm = this.fb.group({
state: [{ value: '', disabled: true }, []], state: [{ value: '', disabled: true }, []],
@@ -145,12 +148,23 @@ export class AppDetailComponent implements OnInit, OnDestroy {
this.mgmtService.GetApplicationById(projectid, id).then(app => { this.mgmtService.GetApplicationById(projectid, id).then(app => {
this.app = app.toObject(); this.app = app.toObject();
this.appNameForm.patchValue(this.app); this.appNameForm.patchValue(this.app);
console.log(this.app);
this.getAuthMethodOptions();
if (this.app.oidcConfig) {
this.initialAuthMethod = this.authMethodFromPartialConfig(this.app.oidcConfig);
this.currentAuthMethod = this.initialAuthMethod;
if (this.initialAuthMethod === CUSTOM_METHOD.key) {
if (!this.authMethods.includes(CUSTOM_METHOD)) {
this.authMethods.push(CUSTOM_METHOD);
}
} else {
this.authMethods = this.authMethods.filter(element => element != CUSTOM_METHOD);
}
}
if (allowed) { if (allowed) {
this.appNameForm.enable(); this.appNameForm.enable();
this.appForm.enable(); this.appForm.enable();
this.redirectControl.enable();
this.postRedirectControl.enable();
} }
if (this.app.oidcConfig?.redirectUrisList) { if (this.app.oidcConfig?.redirectUrisList) {
@@ -161,12 +175,22 @@ export class AppDetailComponent implements OnInit, OnDestroy {
} }
if (this.app.oidcConfig?.clockSkew) { if (this.app.oidcConfig?.clockSkew) {
const inSecs = this.app.oidcConfig?.clockSkew.seconds + this.app.oidcConfig?.clockSkew.nanos / 100000; const inSecs = this.app.oidcConfig?.clockSkew.seconds + this.app.oidcConfig?.clockSkew.nanos / 100000;
console.log(inSecs);
this.appForm.controls['clockSkewSeconds'].setValue(inSecs); this.appForm.controls['clockSkewSeconds'].setValue(inSecs);
} }
if (this.app.oidcConfig) { if (this.app.oidcConfig) {
this.appForm.patchValue(this.app.oidcConfig); this.appForm.patchValue(this.app.oidcConfig);
} }
this.appForm.valueChanges.subscribe(oidcConfig => {
this.initialAuthMethod = this.authMethodFromPartialConfig(oidcConfig);
if (this.initialAuthMethod === CUSTOM_METHOD.key) {
if (!this.authMethods.includes(CUSTOM_METHOD)) {
this.authMethods.push(CUSTOM_METHOD);
}
} else {
this.authMethods = this.authMethods.filter(element => element != CUSTOM_METHOD);
}
});
}).catch(error => { }).catch(error => {
console.error(error); console.error(error);
this.toast.showError(error); this.toast.showError(error);
@@ -176,6 +200,69 @@ export class AppDetailComponent implements OnInit, OnDestroy {
this.docs = (await this.mgmtService.GetZitadelDocs()).toObject(); this.docs = (await this.mgmtService.GetZitadelDocs()).toObject();
} }
private getAuthMethodOptions(): void {
switch (this.app.oidcConfig?.applicationType) {
case OIDCApplicationType.OIDCAPPLICATIONTYPE_NATIVE:
this.authMethods = [
PKCE_METHOD,
CUSTOM_METHOD,
];
break;
case OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB:
this.authMethods = [
PKCE_METHOD,
CODE_METHOD,
POST_METHOD,
];
break;
case OIDCApplicationType.OIDCAPPLICATIONTYPE_USER_AGENT:
this.authMethods = [
PKCE_METHOD,
IMPLICIT_METHOD,
];
break;
}
}
public authMethodFromPartialConfig(config: OIDCConfig.AsObject): string {
const key = getAuthMethodFromPartialConfig(config);
return key;
}
public setPartialConfigFromAuthMethod(authMethod: string): void {
const partialConfig = getPartialConfigFromAuthMethod(authMethod);
if (partialConfig && this.app.oidcConfig) {
this.app.oidcConfig.responseTypesList = partialConfig.responseTypesList ?? [];
this.app.oidcConfig.grantTypesList = partialConfig.grantTypesList ?? [];
this.app.oidcConfig.authMethodType = partialConfig.authMethodType ?? OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE;
this.appForm.patchValue(this.app.oidcConfig);
}
}
public deleteApp(): void {
const dialogRef = this.dialog.open(WarnDialogComponent, {
data: {
confirmKey: 'ACTIONS.DELETE',
cancelKey: 'ACTIONS.CANCEL',
titleKey: 'APP.PAGES.DIALOG.DELETE.TITLE',
descriptionKey: 'APP.PAGES.DIALOG.DELETE.DESCRIPTION',
},
width: '400px',
});
dialogRef.afterClosed().subscribe(resp => {
if (resp && this.projectId && this.app.id) {
this.mgmtService.RemoveApplication(this.projectId, this.app.id).then(() => {
this.toast.showInfo('APP.TOAST.DELETED', true);
this.router.navigate(['/projects', this.projectId]);
}).catch(error => {
this.toast.showError(error);
});
}
});
}
public changeState(event: MatButtonToggleChange): void { public changeState(event: MatButtonToggleChange): void {
if (event.value === AppState.APPSTATE_ACTIVE) { if (event.value === AppState.APPSTATE_ACTIVE) {
this.mgmtService.ReactivateApplication(this.projectId, this.app.id).then(() => { this.mgmtService.ReactivateApplication(this.projectId, this.app.id).then(() => {
@@ -192,40 +279,6 @@ export class AppDetailComponent implements OnInit, OnDestroy {
} }
} }
public add(input: any, target: RedirectType): void {
if (target === RedirectType.POSTREDIRECT && this.postRedirectControl.valid) {
if (input.value !== '' && input.value !== ' ' && input.value !== '/') {
this.postLogoutRedirectUrisList.push(input.value);
}
if (input) {
input.value = '';
}
} else if (target === RedirectType.REDIRECT && this.redirectControl.valid) {
if (input.value !== '' && input.value !== ' ' && input.value !== '/') {
this.redirectUrisList.push(input.value);
}
if (input) {
input.value = '';
}
}
}
public remove(redirect: any, target: RedirectType): void {
if (target === RedirectType.POSTREDIRECT) {
const index = this.postLogoutRedirectUrisList.indexOf(redirect);
if (index >= 0) {
this.postLogoutRedirectUrisList.splice(index, 1);
}
} else if (target === RedirectType.REDIRECT) {
const index = this.redirectUrisList.indexOf(redirect);
if (index >= 0) {
this.redirectUrisList.splice(index, 1);
}
}
}
public saveApp(): void { public saveApp(): void {
if (this.appNameForm.valid) { if (this.appNameForm.valid) {
this.app.name = this.name?.value; this.app.name = this.name?.value;
@@ -234,6 +287,7 @@ export class AppDetailComponent implements OnInit, OnDestroy {
.UpdateApplication(this.projectId, this.app.id, this.name?.value) .UpdateApplication(this.projectId, this.app.id, this.name?.value)
.then(() => { .then(() => {
this.toast.showInfo('APP.TOAST.OIDCUPDATED', true); this.toast.showInfo('APP.TOAST.OIDCUPDATED', true);
this.editState = false;
}) })
.catch(error => { .catch(error => {
this.toast.showError(error); this.toast.showError(error);
@@ -282,10 +336,12 @@ export class AppDetailComponent implements OnInit, OnDestroy {
dur.setNanos((Math.floor(this.clockSkewSeconds?.value % 1) * 10000)); dur.setNanos((Math.floor(this.clockSkewSeconds?.value % 1) * 10000));
req.setClockSkew(dur); req.setClockSkew(dur);
} }
console.log(req.toObject());
this.mgmtService this.mgmtService
.UpdateOIDCAppConfig(req) .UpdateOIDCAppConfig(req)
.then(() => { .then(() => {
if (this.app.oidcConfig) {
this.currentAuthMethod = this.authMethodFromPartialConfig(this.app.oidcConfig);
}
this.toast.showInfo('APP.TOAST.OIDCUPDATED', true); this.toast.showInfo('APP.TOAST.OIDCUPDATED', true);
}) })
.catch(error => { .catch(error => {

View File

@@ -19,6 +19,7 @@ import { MatTooltipModule } from '@angular/material/tooltip';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { CopyToClipboardModule } from 'src/app/directives/copy-to-clipboard/copy-to-clipboard.module'; import { CopyToClipboardModule } from 'src/app/directives/copy-to-clipboard/copy-to-clipboard.module';
import { HasRoleModule } from 'src/app/directives/has-role/has-role.module'; import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
import { AppRadioModule } from 'src/app/modules/app-radio/app-radio.module';
import { CardModule } from 'src/app/modules/card/card.module'; import { CardModule } from 'src/app/modules/card/card.module';
import { ChangesModule } from 'src/app/modules/changes/changes.module'; import { ChangesModule } from 'src/app/modules/changes/changes.module';
import { InfoSectionModule } from 'src/app/modules/info-section/info-section.module'; import { InfoSectionModule } from 'src/app/modules/info-section/info-section.module';
@@ -29,15 +30,20 @@ import { AppCreateComponent } from './app-create/app-create.component';
import { AppDetailComponent } from './app-detail/app-detail.component'; import { AppDetailComponent } from './app-detail/app-detail.component';
import { AppSecretDialogComponent } from './app-secret-dialog/app-secret-dialog.component'; import { AppSecretDialogComponent } from './app-secret-dialog/app-secret-dialog.component';
import { AppsRoutingModule } from './apps-routing.module'; import { AppsRoutingModule } from './apps-routing.module';
import { A11yModule } from '@angular/cdk/a11y';
import { RedirectUrisComponent } from './redirect-uris/redirect-uris.component';
@NgModule({ @NgModule({
declarations: [ declarations: [
AppCreateComponent, AppCreateComponent,
AppDetailComponent, AppDetailComponent,
AppSecretDialogComponent, AppSecretDialogComponent,
RedirectUrisComponent,
], ],
imports: [ imports: [
CommonModule, CommonModule,
A11yModule,
AppRadioModule,
AppsRoutingModule, AppsRoutingModule,
FormsModule, FormsModule,
TranslateModule, TranslateModule,

View File

@@ -0,0 +1,166 @@
import { RadioItemAuthType } from 'src/app/modules/app-radio/app-auth-method-radio/app-auth-method-radio.component';
import { OIDCAuthMethodType, OIDCConfig, OIDCGrantType, OIDCResponseType } from 'src/app/proto/generated/management_pb';
export const CODE_METHOD: RadioItemAuthType = {
key: 'CODE',
titleI18nKey: 'APP.OIDC.SELECTION.AUTHMETHOD.CODE.TITLE',
descI18nKey: 'APP.OIDC.SELECTION.AUTHMETHOD.CODE.DESCRIPTION',
disabled: false,
prefix: 'CODE',
background: 'rgb(89 115 128)',
responseType: OIDCResponseType.OIDCRESPONSETYPE_CODE,
grantType: OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE,
authMethod: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_BASIC,
recommended: false,
};
export const PKCE_METHOD: RadioItemAuthType = {
key: 'PKCE',
titleI18nKey: 'APP.OIDC.SELECTION.AUTHMETHOD.PKCE.TITLE',
descI18nKey: 'APP.OIDC.SELECTION.AUTHMETHOD.PKCE.DESCRIPTION',
disabled: false,
prefix: 'PKCE',
background: 'rgb(80 110 92)',
responseType: OIDCResponseType.OIDCRESPONSETYPE_CODE,
grantType: OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE,
authMethod: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE,
recommended: true,
};
export const POST_METHOD: RadioItemAuthType = {
key: 'POST',
titleI18nKey: 'APP.OIDC.SELECTION.AUTHMETHOD.POST.TITLE',
descI18nKey: 'APP.OIDC.SELECTION.AUTHMETHOD.POST.DESCRIPTION',
disabled: false,
prefix: 'POST',
background: '#595d80',
responseType: OIDCResponseType.OIDCRESPONSETYPE_CODE,
grantType: OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE,
authMethod: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_POST,
notRecommended: true,
};
export const PK_JWT_METHOD: RadioItemAuthType = {
key: 'PK_JWT',
titleI18nKey: 'APP.OIDC.SELECTION.AUTHMETHOD.ALTERNATIVE.TITLE',
descI18nKey: 'APP.OIDC.SELECTION.AUTHMETHOD.ALTERNATIVE.DESCRIPTION',
disabled: false,
prefix: 'PK_JWT',
background: '#6a506e',
responseType: OIDCResponseType.OIDCRESPONSETYPE_CODE,
grantType: OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE,
authMethod: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_POST,
};
export const IMPLICIT_METHOD: RadioItemAuthType = {
key: 'IMPLICIT',
titleI18nKey: 'APP.OIDC.SELECTION.AUTHMETHOD.IMPLICIT.TITLE',
descI18nKey: 'APP.OIDC.SELECTION.AUTHMETHOD.IMPLICIT.DESCRIPTION',
disabled: false,
prefix: 'IMP',
background: 'rgb(144 75 75)',
responseType: OIDCResponseType.OIDCRESPONSETYPE_ID_TOKEN,
grantType: OIDCGrantType.OIDCGRANTTYPE_IMPLICIT,
authMethod: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE,
notRecommended: true,
};
export const CUSTOM_METHOD: RadioItemAuthType = {
key: 'CUSTOM',
titleI18nKey: 'APP.OIDC.SELECTION.AUTHMETHOD.CUSTOM.TITLE',
descI18nKey: 'APP.OIDC.SELECTION.AUTHMETHOD.CUSTOM.DESCRIPTION',
disabled: false,
prefix: 'CUSTOM',
background: '#333',
};
export function getPartialConfigFromAuthMethod(authMethod: string): Partial<OIDCConfig.AsObject> | undefined {
let config: Partial<OIDCConfig.AsObject>;
switch (authMethod) {
case CODE_METHOD.key:
config = {
responseTypesList: [OIDCResponseType.OIDCRESPONSETYPE_CODE],
grantTypesList: [OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE],
authMethodType: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_BASIC,
};
return config;
case PKCE_METHOD.key:
config = {
responseTypesList: [OIDCResponseType.OIDCRESPONSETYPE_CODE],
grantTypesList: [OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE],
authMethodType: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE,
};
return config;
case POST_METHOD.key:
config = {
responseTypesList: [OIDCResponseType.OIDCRESPONSETYPE_CODE],
grantTypesList: [OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE],
authMethodType: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_POST,
};
return config;
// case PK_JWT_METHOD.key:
// config = {
// responseTypesList: [OIDCResponseType.OIDCRESPONSETYPE_CODE],
// grantTypesList: [OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE],
// authMethodType: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE,
// };
// return config;
case IMPLICIT_METHOD.key:
config = {
responseTypesList: [OIDCResponseType.OIDCRESPONSETYPE_ID_TOKEN_TOKEN],
grantTypesList: [OIDCGrantType.OIDCGRANTTYPE_IMPLICIT],
authMethodType: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE,
};
return config;
default:
return undefined;
}
}
export function getAuthMethodFromPartialConfig(config: Partial<OIDCConfig.AsObject> | OIDCConfig.AsObject): string {
const toCheck = [config.responseTypesList, config.grantTypesList, config.authMethodType];
const code = JSON.stringify(
[
[OIDCResponseType.OIDCRESPONSETYPE_CODE],
[OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE],
OIDCAuthMethodType.OIDCAUTHMETHODTYPE_BASIC,
]
);
const pkce = JSON.stringify(
[
[OIDCResponseType.OIDCRESPONSETYPE_CODE],
[OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE],
OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE,
]
);
const post = JSON.stringify(
[
[OIDCResponseType.OIDCRESPONSETYPE_CODE],
[OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE],
OIDCAuthMethodType.OIDCAUTHMETHODTYPE_POST,
]
);
// const pk_jwt = JSON.stringify(
// [
// [OIDCResponseType.OIDCRESPONSETYPE_CODE],
// [OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE],
// OIDCAuthMethodType.OIDCAUTHMETHODTYPE_BASIC,
// ]
// );
const implicit = JSON.stringify(
[
[OIDCResponseType.OIDCRESPONSETYPE_ID_TOKEN_TOKEN],
[OIDCGrantType.OIDCGRANTTYPE_IMPLICIT],
OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE,
]
);
switch (JSON.stringify(toCheck)) {
case code: return CODE_METHOD.key;
case pkce: return PKCE_METHOD.key;
case post: return POST_METHOD.key;
// case pk_jwt: return PK_JWT_METHOD.key;
case implicit: return IMPLICIT_METHOD.key;
default:
return CUSTOM_METHOD.key;
}
}

View File

@@ -0,0 +1,25 @@
import { OIDCApplicationType } from 'src/app/proto/generated/management_pb';
export const WEB_TYPE = {
titleI18nKey: 'APP.OIDC.SELECTION.APPTYPE.WEB.TITLE',
descI18nKey: 'APP.OIDC.SELECTION.APPTYPE.WEB.DESCRIPTION',
type: OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB,
prefix: 'WEB',
background: 'rgb(80, 110, 110)',
};
export const USER_AGENT_TYPE = {
titleI18nKey: 'APP.OIDC.SELECTION.APPTYPE.USERAGENT.TITLE',
descI18nKey: 'APP.OIDC.SELECTION.APPTYPE.USERAGENT.DESCRIPTION',
type: OIDCApplicationType.OIDCAPPLICATIONTYPE_USER_AGENT,
prefix: 'UA',
background: '#6a506e',
};
export const NATIVE_TYPE = {
titleI18nKey: 'APP.OIDC.SELECTION.APPTYPE.NATIVE.TITLE',
descI18nKey: 'APP.OIDC.SELECTION.APPTYPE.NATIVE.DESCRIPTION',
type: OIDCApplicationType.OIDCAPPLICATIONTYPE_NATIVE,
prefix: 'N',
background: '#595d80',
};

View File

@@ -0,0 +1,28 @@
<form class="form" (ngSubmit)="add(redInput)">
<cnsl-form-field class="formfield">
<cnsl-label>{{ title }}</cnsl-label>
<input #redInput cnslInput placeholder="ex. https://" [formControl]="redirectControl">
</cnsl-form-field>
<button matTooltip="{{'ACTIONS.ADD' | translate}}" type="submit" mat-icon-button
[disabled]="redirectControl.invalid || !canWrite">
<mat-icon>add</mat-icon>
</button>
</form>
<div class="uri-list">
<div *ngFor="let uri of urisList" class="uri-line">
<span class="uri"
[ngClass]="{'green': !devMode && uri?.startsWith('https://'), 'red': !devMode && !uri?.startsWith('https://')}">{{uri}}</span>
<span class="fill-space"></span>
<i *ngIf="!devMode && !uri?.startsWith('https://')" class="las la-exclamation red"></i>
<!-- <i *ngIf="!devMode && uri?.startsWith('https://')" class="las la-check green"></i> -->
<button matTooltip="{{'ACTIONS.DELETE' | translate}}" mat-icon-button (click)="remove(uri)" class="icon-button">
<mat-icon>cancel</mat-icon>
</button>
</div>
</div>
<p *ngIf="redirectControl.value && redirectControl.invalid" class="error">
{{'APP.OIDC.REDIRECTNOTVALID' | translate}}</p>

View File

@@ -0,0 +1,61 @@
.form {
display: flex;
align-items: flex-end;
min-width: 320px;
.formfield {
flex: 1;
}
button {
margin-bottom: 14px;
margin-right: -0.5rem;
}
}
.uri-list {
margin: 0 .5rem;
width: 100%;
.uri-line {
display: flex;
align-items: center;
.uri {
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
font-size: 14px;
}
.fill-space {
flex: 1;
}
i.green {
font-size: 1rem;
line-height: 35px;
height: 30px;
}
i.red {
font-size: 1.2rem;
}
.icon-button {
height: 30px;
line-height: 30px;
mat-icon {
font-size: 1rem !important;
}
&:not(:hover) {
color: var(--grey);
}
}
}
}
.error {
font-size: 13px;
color: #f44336;
margin: 0 .5rem 1.5rem .5rem;
}

View File

@@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { RedirectUrisComponent } from './redirect-uris.component';
describe('RedirectUrisComponent', () => {
let component: RedirectUrisComponent;
let fixture: ComponentFixture<RedirectUrisComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ RedirectUrisComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(RedirectUrisComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,43 @@
import { Component, EventEmitter, Input, OnInit } from '@angular/core';
import { FormControl } from '@angular/forms';
@Component({
selector: 'cnsl-redirect-uris',
templateUrl: './redirect-uris.component.html',
styleUrls: ['./redirect-uris.component.scss']
})
export class RedirectUrisComponent implements OnInit {
@Input() title: string = '';
@Input() devMode: boolean = false;
@Input() canWrite: boolean = false;
@Input() public urisList: string[] = [];
@Input() public redirectControl: FormControl = new FormControl({ value: '', disabled: true });
@Input() public changedUris: EventEmitter<string[]> = new EventEmitter();
constructor() { }
ngOnInit(): void {
if (this.canWrite) {
this.redirectControl.enable();
}
}
public add(input: any): void {
if (this.redirectControl.valid) {
if (input.value !== '' && input.value !== ' ' && input.value !== '/') {
this.urisList.push(input.value);
}
if (input) {
input.value = '';
}
}
}
public remove(redirect: any): void {
console.log(redirect);
const index = this.urisList.indexOf(redirect);
if (index >= 0) {
this.urisList.splice(index, 1);
}
}
}

View File

@@ -11,18 +11,27 @@
</div> </div>
<div [routerLink]="['/projects', projectId, 'apps', app.id ]" class="app-wrap" <div [routerLink]="['/projects', projectId, 'apps', app.id ]" class="app-wrap"
*ngFor="let app of appsSubject | async"> *ngFor="let app of appsSubject | async"
<div class="morph-card" matRipple> matTooltip="{{'APP.OIDC.APPTYPE'+app.oidcConfig.applicationType | translate}}">
<cnsl-app-card class="grid-card" matRipple [type]="app.oidcConfig?.applicationType">
{{ app.name.charAt(0)}} {{ app.name.charAt(0)}}
</div> <i *ngIf="app.oidcConfig.applicationType == OIDCApplicationType.OIDCAPPLICATIONTYPE_NATIVE"
class="las la-mobile"></i>
<i *ngIf="app.oidcConfig.applicationType == OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB"
class="las la-code"></i>
<i *ngIf="app.oidcConfig.applicationType == OIDCApplicationType.OIDCAPPLICATIONTYPE_USER_AGENT"
class="las la-code"></i>
</cnsl-app-card>
<span class="name">{{app.name}}</span> <span class="name">{{app.name}}</span>
<span class="type">{{'APP.OIDC.APPTYPE'+app.oidcConfig.applicationType | translate}}</span>
</div> </div>
<ng-template appHasRole [appHasRole]="['project.app.write']"> <ng-template appHasRole [appHasRole]="['project.app.write']">
<div class="app-wrap" *ngIf="!disabled" [routerLink]="[ '/projects', projectId, 'apps', 'create']"> <div class="app-wrap" *ngIf="!disabled" [routerLink]="[ '/projects', projectId, 'apps', 'create']">
<div class="morph-card add" matRipple> <cnsl-app-card class="grid-card add" matRipple>
<mat-icon>add</mat-icon> <mat-icon>add</mat-icon>
</div> </cnsl-app-card>
<span class="name">{{ 'ACTIONS.NEW' | translate }}</span> <span class="name">{{ 'ACTIONS.NEW' | translate }}</span>
</div> </div>
</ng-template> </ng-template>

View File

@@ -1,82 +1,62 @@
@import '~@angular/material/theming';
@mixin application-grid-theme($theme) {
/* stylelint-disable */
$primary: map-get($theme, primary);
$primary-dark: mat-color($primary, A900);
$accent: map-get($theme, accent);
$accent-color: mat-color($primary, 500);
/* stylelint-enable */
.app-grid-header { .app-grid-header {
display: flex; display: flex;
align-items: center; align-items: center;
.fill-space { .fill-space {
flex: 1; flex: 1;
} }
} }
.app-container { .app-container {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
margin: 0 -1rem; margin: 0 -1rem;
padding-bottom: 2rem; padding-bottom: 2rem;
.sp-container { .sp-container {
display: flex;
justify-content: center;
align-items: center;
width: calc(82px + 2rem);
height: calc(82px + 2rem);
}
.app-wrap {
outline: none;
display: flex;
flex-direction: column;
align-items: center;
max-width: 150px;
.morph-card {
cursor: pointer;
animation: all .2s;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
font-size: 2rem; width: calc(82px + 2rem);
height: 80px; height: calc(82px + 2rem);
width: 80px; }
margin: 1rem;
text-transform: uppercase; .app-wrap {
border-radius: .5rem; outline: none;
border: 2px solid $accent-color; display: flex;
font-weight: 800; flex-direction: column;
background-color: $primary-dark; align-items: center;
transition: background-color box-shadow .3s ease-in; max-width: 150px;
background-image:
linear-gradient(transparent 11px, rgba($accent-color, .5) 12px, transparent 12px), .grid-card {
linear-gradient(90deg, transparent 11px, rgba($accent-color, .5) 12px, transparent 12px); cursor: pointer;
background-size: 100% 12px, 12px 100%; display: flex;
flex-direction: column;
&:hover { justify-content: center;
background-color: rgba($accent-color, .1); align-items: center;
} font-size: 2rem;
height: 80px;
&.add { width: 80px;
background: $accent-color; margin: 1rem;
color: white; text-transform: uppercase;
border-radius: .5rem;
&:hover { font-weight: 800;
background-color: rgba($accent-color, .8); box-sizing: border-box;
}
} &.add {
} border: 2px solid var(--grey);
}
.name { }
font-size: .8rem;
color: #8a868a; .name {
} font-size: 14px;
}
.type {
font-size: 12px;
color: #8a868a;
}
} }
}
} }

View File

@@ -1,8 +1,9 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { BehaviorSubject, from, Observable, of } from 'rxjs'; import { BehaviorSubject, from, Observable, of } from 'rxjs';
import { catchError, finalize, map } from 'rxjs/operators'; import { catchError, finalize, map } from 'rxjs/operators';
import { Application } from 'src/app/proto/generated/management_pb'; import { Application, OIDCApplicationType, OIDCResponseType } from 'src/app/proto/generated/management_pb';
import { ManagementService } from 'src/app/services/mgmt.service'; import { ManagementService } from 'src/app/services/mgmt.service';
import { NATIVE_TYPE, USER_AGENT_TYPE, WEB_TYPE } from '../../../apps/authtypes';
@Component({ @Component({
selector: 'app-application-grid', selector: 'app-application-grid',
@@ -16,6 +17,11 @@ export class ApplicationGridComponent implements OnInit {
public appsSubject: BehaviorSubject<Application.AsObject[]> = new BehaviorSubject<Application.AsObject[]>([]); public appsSubject: BehaviorSubject<Application.AsObject[]> = new BehaviorSubject<Application.AsObject[]>([]);
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true); private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true);
public loading$: Observable<boolean> = this.loadingSubject.asObservable(); public loading$: Observable<boolean> = this.loadingSubject.asObservable();
public OIDCApplicationType: any = OIDCApplicationType;
public NATIVE_TYPE: any = NATIVE_TYPE;
public WEB_TYPE: any = WEB_TYPE;
public USER_AGENT_TYPE: any = USER_AGENT_TYPE;
constructor(private mgmtService: ManagementService) { } constructor(private mgmtService: ManagementService) { }

View File

@@ -24,10 +24,17 @@
</ng-container> </ng-container>
<ng-container matColumnDef="name"> <ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef> {{ 'PROJECT.ROLE.NAME' | translate }} </th> <th mat-header-cell *matHeaderCellDef> {{ 'APP.NAME' | translate }} </th>
<td class="pointer" [routerLink]="['/projects', projectId, 'apps', role.id ]" mat-cell <td class="pointer" [routerLink]="['/projects', projectId, 'apps', app.id ]" mat-cell
*matCellDef="let role"> *matCellDef="let app">
{{role.name}} </td> {{app.name}} </td>
</ng-container>
<ng-container matColumnDef="type">
<th mat-header-cell *matHeaderCellDef> {{ 'APP.OIDC.APPTYPE' | translate }} </th>
<td class="pointer" [routerLink]="['/projects', projectId, 'apps', app.id ]" mat-cell
*matCellDef="let app">
{{'APP.OIDC.APPTYPE'+app?.oidcConfig?.applicationType | translate}} </td>
</ng-container> </ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>

View File

@@ -26,7 +26,7 @@ export class ApplicationsComponent implements AfterViewInit, OnInit {
public dataSource!: ProjectApplicationsDataSource; public dataSource!: ProjectApplicationsDataSource;
public selection: SelectionModel<Application.AsObject> = new SelectionModel<Application.AsObject>(true, []); public selection: SelectionModel<Application.AsObject> = new SelectionModel<Application.AsObject>(true, []);
public displayedColumns: string[] = ['select', 'name']; public displayedColumns: string[] = ['select', 'name', 'type'];
constructor(private mgmtService: ManagementService, private toast: ToastService) { } constructor(private mgmtService: ManagementService, private toast: ToastService) { }

View File

@@ -8,7 +8,7 @@
<ng-template appHasRole [appHasRole]="['project.write:'+projectId, 'project.write']"> <ng-template appHasRole [appHasRole]="['project.write:'+projectId, 'project.write']">
<button matTooltip="{{'ACTIONS.EDIT' | translate}}" mat-icon-button (click)="editstate = !editstate" <button matTooltip="{{'ACTIONS.EDIT' | translate}}" mat-icon-button (click)="editstate = !editstate"
aria-label="Edit project name" *ngIf="isZitadel === false"> aria-label="Edit project name" *ngIf="isZitadel === false">
<mat-icon *ngIf="!editstate">edit</mat-icon> <i *ngIf="!editstate" class="las la-edit"></i>
<mat-icon *ngIf="editstate">close</mat-icon> <mat-icon *ngIf="editstate">close</mat-icon>
</button> </button>
</ng-template> </ng-template>
@@ -24,11 +24,13 @@
<button mat-stroked-button color="warn" <button mat-stroked-button color="warn"
[disabled]="isZitadel || (['project.write$', 'project.write:'+ project.projectId]| hasRole | async) == false" [disabled]="isZitadel || (['project.write$', 'project.write:'+ project.projectId]| hasRole | async) == false"
*ngIf="project?.state === ProjectState.PROJECTSTATE_ACTIVE" *ngIf="project?.state === ProjectState.PROJECTSTATE_ACTIVE"
(click)="changeState(ProjectState.PROJECTSTATE_INACTIVE)">{{'PROJECT.TABLE.DEACTIVATE' | translate}}</button> (click)="changeState(ProjectState.PROJECTSTATE_INACTIVE)">{{'PROJECT.TABLE.DEACTIVATE' |
translate}}</button>
<button mat-stroked-button color="warn" <button mat-stroked-button color="warn"
[disabled]="isZitadel || (['project.write$', 'project.write:'+ project.projectId]| hasRole | async) == false" [disabled]="isZitadel || (['project.write$', 'project.write:'+ project.projectId]| hasRole | async) == false"
*ngIf="project?.state === ProjectState.PROJECTSTATE_INACTIVE" *ngIf="project?.state === ProjectState.PROJECTSTATE_INACTIVE"
(click)="changeState(ProjectState.PROJECTSTATE_ACTIVE)">{{'PROJECT.TABLE.ACTIVATE' | translate}}</button> (click)="changeState(ProjectState.PROJECTSTATE_ACTIVE)">{{'PROJECT.TABLE.ACTIVATE' |
translate}}</button>
<div class="full-width"> <div class="full-width">
<div class="line"> <div class="line">
@@ -78,7 +80,7 @@
</ng-template> </ng-template>
<ng-template appHasRole [appHasRole]="['project.role.read:' + project.projectId, 'project.role.read']"> <ng-template appHasRole [appHasRole]="['project.role.read:' + project.projectId, 'project.role.read']">
<app-card title="{{ 'PROJECT.ROLE.TITLE' | translate }}" <app-card id="roles" title="{{ 'PROJECT.ROLE.TITLE' | translate }}"
description="{{ 'PROJECT.ROLE.DESCRIPTION' | translate }}"> description="{{ 'PROJECT.ROLE.DESCRIPTION' | translate }}">
<p>{{'PROJECT.ROLE.OPTIONS' | translate}}</p> <p>{{'PROJECT.ROLE.OPTIONS' | translate}}</p>
<mat-checkbox [(ngModel)]="project.projectRoleAssertion" (change)="saveProject()" <mat-checkbox [(ngModel)]="project.projectRoleAssertion" (change)="saveProject()"
@@ -118,7 +120,8 @@
<div class="meta-row"> <div class="meta-row">
<span class="first">{{'PROJECT.STATE.TITLE' | translate}}:</span> <span class="first">{{'PROJECT.STATE.TITLE' | translate}}:</span>
<span *ngIf="project && project.state !== undefined" class="state" <span *ngIf="project && project.state !== undefined" class="state"
[ngClass]="{'active': project.state === ProjectState.PROJECTSTATE_ACTIVE, 'inactive': project.state === ProjectState.PROJECTSTATE_INACTIVE}">{{'PROJECT.STATE.'+project.state | translate}}</span> [ngClass]="{'active': project.state === ProjectState.PROJECTSTATE_ACTIVE, 'inactive': project.state === ProjectState.PROJECTSTATE_INACTIVE}">{{'PROJECT.STATE.'+project.state
| translate}}</span>
</div> </div>
</div> </div>

View File

@@ -14,6 +14,7 @@ import { MatTooltipModule } from '@angular/material/tooltip';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { HasRoleModule } from 'src/app/directives/has-role/has-role.module'; import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
import { MemberCreateDialogModule } from 'src/app/modules/add-member-dialog/member-create-dialog.module'; import { MemberCreateDialogModule } from 'src/app/modules/add-member-dialog/member-create-dialog.module';
import { AppCardModule } from 'src/app/modules/app-card/app-card.module';
import { CardModule } from 'src/app/modules/card/card.module'; import { CardModule } from 'src/app/modules/card/card.module';
import { ChangesModule } from 'src/app/modules/changes/changes.module'; import { ChangesModule } from 'src/app/modules/changes/changes.module';
import { ContributorsModule } from 'src/app/modules/contributors/contributors.module'; import { ContributorsModule } from 'src/app/modules/contributors/contributors.module';
@@ -43,6 +44,7 @@ import { ProjectGrantsComponent } from './project-grants/project-grants.componen
imports: [ imports: [
CommonModule, CommonModule,
FormsModule, FormsModule,
AppCardModule,
OwnedProjectDetailRoutingModule, OwnedProjectDetailRoutingModule,
TranslateModule, TranslateModule,
ReactiveFormsModule, ReactiveFormsModule,

View File

@@ -39,7 +39,7 @@
<h1 class="h1">{{ 'PROJECT.GRANT.DETAIL.MEMBERTITLE' | translate }}</h1> <h1 class="h1">{{ 'PROJECT.GRANT.DETAIL.MEMBERTITLE' | translate }}</h1>
<p class="desc">{{ 'PROJECT.GRANT.DETAIL.MEMBERDESC' | translate }}</p> <p class="desc">{{ 'PROJECT.GRANT.DETAIL.MEMBERDESC' | translate }}</p>
<app-members-table *ngIf="grant" style="width: 100%;" [dataSource]="dataSource" <app-members-table *ngIf="grant" style="width: 100%;" [dataSource]="dataSource" [canWrite]="['project.grant.member.write','project.grant.member.write:' + grant.id] | hasRole | async"
[memberRoleOptions]="memberRoleOptions" (updateRoles)="updateMemberRoles($event.member, $event.change)" [memberRoleOptions]="memberRoleOptions" (updateRoles)="updateMemberRoles($event.member, $event.change)"
[factoryLoadFunc]="changePageFactory" (changedSelection)="selection = $event" [refreshTrigger]="changePage"> [factoryLoadFunc]="changePageFactory" (changedSelection)="selection = $event" [refreshTrigger]="changePage">
<button selectactions (click)="removeProjectMemberSelection()" <button selectactions (click)="removeProjectMemberSelection()"

View File

@@ -7,8 +7,9 @@
</ng-template> </ng-template>
<p>{{'USER.SIGNEDOUT' | translate}}</p> <p>{{'USER.SIGNEDOUT' | translate}}</p>
<button color="primary" mat-raised-button <button matTooltip="{{'ACTIONS.LOGIN' | translate}}" color="primary" mat-raised-button
[routerLink]="[ '/users/me' ]">{{'USER.SIGNEDOUT_BTN' | translate}}</button> [routerLink]="[ '/users/me' ]">{{'USER.SIGNEDOUT_BTN' |
translate}} <i class="las la-sign-in-alt"></i></button>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -17,19 +17,24 @@
p { p {
color: var(--grey); color: var(--grey);
text-align: center; text-align: center;
font-size: 1rem; font-size: 14px;
margin: 0; margin: 0;
margin-bottom: 3rem; margin-bottom: 3rem;
} }
img { img {
height: 100px; height: 100px;
max-width: 170px;
margin-bottom: 2rem; margin-bottom: 2rem;
} }
button { button {
display: block; display: block;
padding: .5rem 4rem; padding: .5rem 4rem;
i {
margin-left: .5rem;
}
} }
} }
} }

View File

@@ -77,7 +77,7 @@
</div> </div>
</div> </div>
<ng-template appHasRole [appHasRole]="['user.membership.read']"> <ng-template appHasRole [appHasRole]="['user.membership.read']">
<app-memberships [user]="user"></app-memberships> <app-memberships [auth]="true" [user]="user"></app-memberships>
</ng-template> </ng-template>
<app-changes class="changes" [refresh]="refreshChanges$" [changeType]="ChangeType.MYUSER" [id]="user.id"> <app-changes class="changes" [refresh]="refreshChanges$" [changeType]="ChangeType.MYUSER" [id]="user.id">

View File

@@ -3,8 +3,10 @@ import { Component, Input, OnInit } from '@angular/core';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { CreationType, MemberCreateDialogComponent } from 'src/app/modules/add-member-dialog/member-create-dialog.component'; import { CreationType, MemberCreateDialogComponent } from 'src/app/modules/add-member-dialog/member-create-dialog.component';
import { AuthServiceClient } from 'src/app/proto/generated/auth_grpc_web_pb';
import { MemberType, UserMembershipSearchResponse, UserView } from 'src/app/proto/generated/management_pb'; import { MemberType, UserMembershipSearchResponse, UserView } from 'src/app/proto/generated/management_pb';
import { AdminService } from 'src/app/services/admin.service'; import { AdminService } from 'src/app/services/admin.service';
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
import { ManagementService } from 'src/app/services/mgmt.service'; import { ManagementService } from 'src/app/services/mgmt.service';
import { ToastService } from 'src/app/services/toast.service'; import { ToastService } from 'src/app/services/toast.service';
@@ -33,12 +35,14 @@ export class MembershipsComponent implements OnInit {
public loading: boolean = false; public loading: boolean = false;
public memberships!: UserMembershipSearchResponse.AsObject; public memberships!: UserMembershipSearchResponse.AsObject;
@Input() public auth: boolean = false;
@Input() public user!: UserView.AsObject; @Input() public user!: UserView.AsObject;
@Input() public disabled: boolean = false; @Input() public disabled: boolean = false;
public MemberType: any = MemberType; public MemberType: any = MemberType;
constructor( constructor(
private authService: GrpcAuthService,
private mgmtService: ManagementService, private mgmtService: ManagementService,
private adminService: AdminService, private adminService: AdminService,
private dialog: MatDialog, private dialog: MatDialog,
@@ -51,10 +55,17 @@ export class MembershipsComponent implements OnInit {
} }
public async loadManager(userId: string): Promise<void> { public async loadManager(userId: string): Promise<void> {
this.mgmtService.SearchUserMemberships(userId, 100, 0, []).then(response => { if (this.auth) {
this.memberships = response.toObject(); this.authService.SearchUserMemberships(100, 0, []).then(response => {
this.loading = false; this.memberships = response.toObject();
}); this.loading = false;
});
} else {
this.mgmtService.SearchUserMemberships(userId, 100, 0, []).then(response => {
this.memberships = response.toObject();
this.loading = false;
});
}
} }
public navigateToObject(): void { public navigateToObject(): void {

View File

@@ -1,7 +1,6 @@
.head { .head {
display: flex; display: flex;
align-items: center; align-items: center;
border-bottom: 1px solid #ffffff20;
flex-wrap: wrap; flex-wrap: wrap;
padding-bottom: .5rem; padding-bottom: .5rem;

View File

@@ -26,6 +26,9 @@ import {
UpdateUserProfileRequest, UpdateUserProfileRequest,
UserAddress, UserAddress,
UserEmail, UserEmail,
UserMembershipSearchQuery,
UserMembershipSearchRequest,
UserMembershipSearchResponse,
UserPhone, UserPhone,
UserProfile, UserProfile,
UserProfileView, UserProfileView,
@@ -241,6 +244,16 @@ export class GrpcAuthService {
); );
} }
public SearchUserMemberships(limit: number, offset: number, queryList?: UserMembershipSearchQuery[]): Promise<UserMembershipSearchResponse> {
const req = new UserMembershipSearchRequest();
req.setLimit(limit);
req.setOffset(offset);
if (queryList) {
req.setQueriesList(queryList);
}
return this.grpcService.auth.searchMyUserMemberships(req);
}
public GetMyUserEmail(): Promise<UserEmail> { public GetMyUserEmail(): Promise<UserEmail> {
return this.grpcService.auth.getMyUserEmail( return this.grpcService.auth.getMyUserEmail(
new Empty(), new Empty(),

View File

@@ -55,6 +55,7 @@ export class AuthInterceptor<TReq = unknown, TResp = unknown> implements UnaryIn
titleKey: 'ERRORS.TOKENINVALID.TITLE', titleKey: 'ERRORS.TOKENINVALID.TITLE',
descriptionKey: 'ERRORS.TOKENINVALID.DESCRIPTION', descriptionKey: 'ERRORS.TOKENINVALID.DESCRIPTION',
}, },
disableClose: true,
width: '400px', width: '400px',
}); });

View File

@@ -1362,4 +1362,11 @@ export class ManagementService {
public UpdateOIDCAppConfig(req: OIDCConfigUpdate): Promise<OIDCConfig> { public UpdateOIDCAppConfig(req: OIDCConfigUpdate): Promise<OIDCConfig> {
return this.grpcService.mgmt.updateApplicationOIDCConfig(req); return this.grpcService.mgmt.updateApplicationOIDCConfig(req);
} }
public RemoveApplication(projectId: string, appId: string): Promise<Empty> {
const req = new ApplicationID();
req.setId(appId);
req.setProjectId(projectId);
return this.grpcService.mgmt.removeApplication(req);
}
} }

View File

@@ -1,5 +1,29 @@
{ {
"APP_NAME": "ZITADEL", "APP_NAME": "ZITADEL",
"ONBOARDING": {
"HEADER":"Erste Schritte",
"TITLE":"Lernen Sie unsere ZITADEL Console kennen.",
"LOGINDESC":"Melden Sie sich an um Zugriff auf Funktionen von Zitadel zu erhalten",
"LOGIN":"Anmelden",
"DESCRIPTION":"Führen Sie die folgenden Schritte aus und passen Sie ZITADEL optimal an Ihre Bedürfnisse an.",
"STEPS_TITLE":"Führen Sie die folgenden Schritte in gewünschter Reihenfolge aus:",
"STEPS": {
"1": {
"TITLE":"Projekt erstellen",
"DESC":"Erstellen Sie Ihr erstes Projekt und legen Sie Zugangsberechtigungen eventueller Mitarbeiter fest."
},
"2": {
"TITLE":"Applikation erstellen",
"DESC":"Erstellen Sie eine Applikation innerhalb Ihres Projektes und legen Sie dessen Eigenschaften fest."
},
"3": {
"TITLE":"Sicherheit verbessern",
"DESC":"Erweitern Sie die Zugangsrichtlinien und erhöhen Sie dadurch die Sicherheit ihrer Benutzer."
}
},
"START":"Start",
"DOCS":"Docs"
},
"HOME": { "HOME": {
"TITLE": "ZITADEL", "TITLE": "ZITADEL",
"SECURITYANDPRIVACY": "Datenschutz und Personalisierung", "SECURITYANDPRIVACY": "Datenschutz und Personalisierung",
@@ -32,9 +56,15 @@
"WELCOME":"Willkommen", "WELCOME":"Willkommen",
"WELCOMESENTENCE":"Hier findest Du die empfohlenen Aktionen basierend auf Deinen zuletzt erworbenen Berechtigungen. Beachte bitte, dass Du möglicherweise Deine Organisation in der Kopfzeile wechseln musst.", "WELCOMESENTENCE":"Hier findest Du die empfohlenen Aktionen basierend auf Deinen zuletzt erworbenen Berechtigungen. Beachte bitte, dass Du möglicherweise Deine Organisation in der Kopfzeile wechseln musst.",
"DISCLAIMER":"Du kannst nur die Einstellungen Deiner aktuellen Organisation, die in der Kopfzeile angegeben ist, sehen. ZITADEL behandelt Deine Daten vertraulich und sicher.", "DISCLAIMER":"Du kannst nur die Einstellungen Deiner aktuellen Organisation, die in der Kopfzeile angegeben ist, sehen. ZITADEL behandelt Deine Daten vertraulich und sicher.",
"DISCLAIMERLINK":"Mehr Informationen zur Sicherheit" "DISCLAIMERLINK":"Mehr Informationen zur Sicherheit",
"QUICKSTARTS": {
"LABEL":"Erste Schritte",
"TITLE":"Quickstarts",
"DESCRIPTION":"Mit ZITADEL schnell durchstarten."
}
}, },
"MENU": { "MENU": {
"DASHBOARD":"Übersicht",
"PERSONAL_INFO": "Persönliche Informationen", "PERSONAL_INFO": "Persönliche Informationen",
"DOCUMENTATION":"Dokumentation", "DOCUMENTATION":"Dokumentation",
"IAMPOLICIES":"IAM", "IAMPOLICIES":"IAM",
@@ -54,6 +84,7 @@
"SHOWORGS":"Alle Organisationen anzeigen", "SHOWORGS":"Alle Organisationen anzeigen",
"GRANTSECTION":"Berechtigungssektion", "GRANTSECTION":"Berechtigungssektion",
"GRANTS":"Berechtigungen", "GRANTS":"Berechtigungen",
"TOC":"Datenschutz und AGB",
"TOOLTIP": { "TOOLTIP": {
"PERSONAL":"Verwalte deinen persönlichen Account, deine IDPs, Login Methoden, Faktoren und Berechtigungen", "PERSONAL":"Verwalte deinen persönlichen Account, deine IDPs, Login Methoden, Faktoren und Berechtigungen",
"IAMPOLICIES":"Verwalte ZITADELs globale Zugangsrichtlinien und verwalte ZITADEL Manager", "IAMPOLICIES":"Verwalte ZITADELs globale Zugangsrichtlinien und verwalte ZITADEL Manager",
@@ -930,12 +961,34 @@
"1": "Aktiv", "1": "Aktiv",
"2": "Inaktiv" "2": "Inaktiv"
} }
},
"DIALOG": {
"DELETE": {
"TITLE": "App löschen",
"DESCRIPTION":"Wollen Sie diese App wirklich löschen?"
}
},
"NEXTSTEPS": {
"TITLE":"Nächste Schritte",
"0": {
"TITLE":"Rollen festlegen",
"DESC":"Erfassen Sie Rollen für ihr Projekt"
},
"1": {
"TITLE":"Benutzer hinzufügen",
"DESC":"Fügen Sie Nutzer ihrer Organisation hinzu"
},
"2": {
"TITLE":"Hilfe & Support",
"DESC":"Lesen Sie unsere Dokumentation zum Erstellen von Applikation oder kontaktieren Sie unseren Support"
}
} }
}, },
"NAME": "Name", "NAME": "Name",
"TYPE":"Anwendungstyp", "TYPE":"Anwendungstyp",
"GRANT":"Berechtigungstypen", "GRANT":"Berechtigungstypen",
"OIDC": { "OIDC": {
"CURRENT":"Aktuelle Konfiguration",
"TOKENSECTIONTITLE":"AuthToken Optionen", "TOKENSECTIONTITLE":"AuthToken Optionen",
"REDIRECTSECTIONTITLE":"Weiterleitungseinstellungen", "REDIRECTSECTIONTITLE":"Weiterleitungseinstellungen",
"PROSWITCH":"Konfigurator überspringen", "PROSWITCH":"Konfigurator überspringen",
@@ -991,13 +1044,58 @@
"IDTOKENROLEASSERTION_DESCRIPTION":"Bei Auswahl werden dem Id Token die Rollen des Authentifizierten Benutzers hinzugefügt.", "IDTOKENROLEASSERTION_DESCRIPTION":"Bei Auswahl werden dem Id Token die Rollen des Authentifizierten Benutzers hinzugefügt.",
"IDTOKENUSERINFOASSERTION":"User Info im ID Token", "IDTOKENUSERINFOASSERTION":"User Info im ID Token",
"IDTOKENUSERINFOASSERTION_DESCRIPTION":"Ermöglich OIDC clients claims von profile, email, phone und address direkt vom ID Token zu beziehen.", "IDTOKENUSERINFOASSERTION_DESCRIPTION":"Ermöglich OIDC clients claims von profile, email, phone und address direkt vom ID Token zu beziehen.",
"CLOCKSKEW":"ermöglicht Clients, den Taktversatz von OP und Client zu verarbeiten. Die Dauer (0-5s) wird der exp addiert und von iats, auth_time und nbf abgezogen." "CLOCKSKEW":"ermöglicht Clients, den Taktversatz von OP und Client zu verarbeiten. Die Dauer (0-5s) wird der exp addiert und von iats, auth_time und nbf abgezogen.",
"RECOMMENDED":"Empfohlen",
"NOTRECOMMENDED":"nicht empfohlen",
"SELECTION":{
"APPTYPE": {
"WEB": {
"TITLE":"Web",
"DESCRIPTION":"Standard Web applications wie .net, PHP, Node.js, Java, etc."
},
"NATIVE": {
"TITLE":"NATIVE",
"DESCRIPTION":"Mobile Apps, Desktop, Smart Devices, etc."
},
"USERAGENT": {
"TITLE":"User Agent",
"DESCRIPTION":"Single Page Applications (SPA) und grundsätzlich alle im Browser aufgeführten JS Frameworks"
}
},
"AUTHMETHOD": {
"CODE": {
"TITLE":"Code",
"DESCRIPTION":"Tausche den Authorization Code gegen Tokens ein"
},
"PKCE": {
"TITLE":"PKCE",
"DESCRIPTION":"Nutze einen Zufalls Hash Wert anstelle des Client Secret für mehr Sicherheit"
},
"POST": {
"TITLE":"POST",
"DESCRIPTION":"Sende client_id und client_secret im (HTML) Formular"
},
"PK_JWT": {
"TITLE":"Private Key JWT",
"DESCRIPTION":"Nutze einen Private Key um deine Application zu authentifizieren"
},
"IMPLICIT": {
"TITLE":"Implicit",
"DESCRIPTION":"Erhalte die Token direkt vom authorize Endpoint"
},
"CUSTOM": {
"TITLE":"Custom",
"DESCRIPTION":"Deine Konfiguration entspricht keiner anderen Option."
}
}
}
}, },
"TOAST": { "TOAST": {
"REACTIVATED":"Anwendung reaktiviert.", "REACTIVATED":"Anwendung reaktiviert.",
"DEACTIVATED":"Anwendung deaktiviert.", "DEACTIVATED":"Anwendung deaktiviert.",
"OIDCUPDATED":"OIDC-Konfiguration geändert.", "OIDCUPDATED":"OIDC-Konfiguration geändert.",
"OIDCCLIENTSECRETREGENERATED":"OIDC-Client Secret generiert." "OIDCCLIENTSECRETREGENERATED":"OIDC-Client Secret generiert.",
"DELETED":"App gelöscht."
} }
}, },
"GENDERS": { "GENDERS": {

View File

@@ -1,5 +1,29 @@
{ {
"APP_NAME": "ZITADEL", "APP_NAME": "ZITADEL",
"ONBOARDING": {
"HEADER":"First Steps",
"TITLE":"Learn how to use ZITADEL",
"LOGINDESC":"You need to log in to control your ZITADEL settings.",
"LOGIN":"Login",
"DESCRIPTION":"We at ZITADEL care a lot about security and performance. Carry out the following steps and adapt ZITADEL optimally to your needs.",
"STEPS_TITLE":"Complete the following steps in the order you want:",
"STEPS": {
"1": {
"TITLE":"Create a project",
"DESC":"Create your first project and define access rights for any employees."
},
"2": {
"TITLE":"Create Application",
"DESC":"Create an application within your project and define its properties."
},
"3": {
"TITLE":"Improve security",
"DESC":"Extend the access policies and thereby increase the security of your users."
}
},
"START":"Start",
"DOCS":"Docs"
},
"HOME": { "HOME": {
"TITLE": "ZITADEL", "TITLE": "ZITADEL",
"SECURITYANDPRIVACY": "Data Protection and Personalisation", "SECURITYANDPRIVACY": "Data Protection and Personalisation",
@@ -32,9 +56,15 @@
"WELCOME":"Welcome", "WELCOME":"Welcome",
"WELCOMESENTENCE":"Here you can find recommended actions based on your last acquired permissions. Note that you may have to select your organisation in the header above.", "WELCOMESENTENCE":"Here you can find recommended actions based on your last acquired permissions. Note that you may have to select your organisation in the header above.",
"DISCLAIMER":"You can only see settings of your current organisation specified in the header. ZITADEL treats your data confidentially and securely.", "DISCLAIMER":"You can only see settings of your current organisation specified in the header. ZITADEL treats your data confidentially and securely.",
"DISCLAIMERLINK":"Further information" "DISCLAIMERLINK":"Further information",
"QUICKSTARTS": {
"LABEL":"First Steps",
"TITLE":"Quickstarts",
"DESCRIPTION":"Get started with ZITADEL quickly."
}
}, },
"MENU": { "MENU": {
"DASHBOARD":"Overview",
"PERSONAL_INFO": "Personal Information", "PERSONAL_INFO": "Personal Information",
"DOCUMENTATION":"Documentation", "DOCUMENTATION":"Documentation",
"IAMPOLICIES":"IAM", "IAMPOLICIES":"IAM",
@@ -54,6 +84,7 @@
"SHOWORGS":"Show All Organisations", "SHOWORGS":"Show All Organisations",
"GRANTSECTION":"Authorization Section", "GRANTSECTION":"Authorization Section",
"GRANTS":"Authorizations", "GRANTS":"Authorizations",
"TOC":"Privacy Policy and TOC",
"TOOLTIP": { "TOOLTIP": {
"PERSONAL":"Show your Personal Account, your IDPs, Login methods, Factors and Authorisations", "PERSONAL":"Show your Personal Account, your IDPs, Login methods, Factors and Authorisations",
"IAMPOLICIES":"Manage ZITADELs global Access policies und elect ZITADEL Managers", "IAMPOLICIES":"Manage ZITADELs global Access policies und elect ZITADEL Managers",
@@ -930,12 +961,34 @@
"1": "Active", "1": "Active",
"2": "Inactive" "2": "Inactive"
} }
},
"DIALOG": {
"DELETE": {
"TITLE": "Delete App",
"DESCRIPTION":"Do you really want to delete this application?"
}
},
"NEXTSTEPS": {
"TITLE":"Next Steps",
"0": {
"TITLE":"Add roles",
"DESC":"Enter your project roles"
},
"1": {
"TITLE":"Add users",
"DESC":"Add new users of your organization"
},
"2": {
"TITLE":"Help & Support",
"DESC":"Read our documentation on creating applications or contact our support"
}
} }
}, },
"NAME": "Name", "NAME": "Name",
"TYPE":"Application Type", "TYPE":"Application Type",
"GRANT":"Grant Types", "GRANT":"Grant Types",
"OIDC": { "OIDC": {
"CURRENT":"Current Config",
"TOKENSECTIONTITLE":"AuthToken Options", "TOKENSECTIONTITLE":"AuthToken Options",
"REDIRECTSECTIONTITLE":"Redirect Settings", "REDIRECTSECTIONTITLE":"Redirect Settings",
"PROSWITCH":"I'm a pro. Skip this wizard.", "PROSWITCH":"I'm a pro. Skip this wizard.",
@@ -991,13 +1044,58 @@
"IDTOKENROLEASSERTION_DESCRIPTION":"If selected, the roles of the authenticated user are added to the ID token.", "IDTOKENROLEASSERTION_DESCRIPTION":"If selected, the roles of the authenticated user are added to the ID token.",
"IDTOKENUSERINFOASSERTION":"User Info inside ID Token", "IDTOKENUSERINFOASSERTION":"User Info inside ID Token",
"IDTOKENUSERINFOASSERTION_DESCRIPTION":"Enables clients to retrieve profile, email, phone and address claims from ID token.", "IDTOKENUSERINFOASSERTION_DESCRIPTION":"Enables clients to retrieve profile, email, phone and address claims from ID token.",
"CLOCKSKEW":"Enables clients to handle clock skew of OP and client. The duration (0-5s) will be added to exp claim and subtracted from iats, auth_time and nbf." "CLOCKSKEW":"Enables clients to handle clock skew of OP and client. The duration (0-5s) will be added to exp claim and subtracted from iats, auth_time and nbf.",
"RECOMMENDED":"recommended",
"NOTRECOMMENDED":"not recommended",
"SELECTION":{
"APPTYPE": {
"WEB": {
"TITLE":"Web",
"DESCRIPTION":"Regular Web applications like .net, PHP, Node.js, Java, etc."
},
"NATIVE": {
"TITLE":"NATIVE",
"DESCRIPTION":"Mobile Apps, Desktop, Smart Devices, etc."
},
"USERAGENT": {
"TITLE":"User Agent",
"DESCRIPTION":"Single Page Applications (SPA) and in general all JS frameworks executed in browsers"
}
},
"AUTHMETHOD": {
"CODE": {
"TITLE":"Code",
"DESCRIPTION":"Exchange the authorization code for the tokens"
},
"PKCE": {
"TITLE":"PKCE",
"DESCRIPTION":"Use a random hash instead of a static client secret for more security"
},
"POST": {
"TITLE":"POST",
"DESCRIPTION":"Send client_id and client_secret as part of the form"
},
"PK_JWT": {
"TITLE":"Private Key JWT",
"DESCRIPTION":"Use a private key to authorize your application"
},
"IMPLICIT": {
"TITLE":"Implicit",
"DESCRIPTION":"Get the tokens directly from the authorization endpoint"
},
"CUSTOM": {
"TITLE":"Custom",
"DESCRIPTION":"Your setting doesn't correspond to any other option."
}
}
}
}, },
"TOAST": { "TOAST": {
"REACTIVATED":"Application reactivated.", "REACTIVATED":"Application reactivated.",
"DEACTIVATED":"Application deactivated.", "DEACTIVATED":"Application deactivated.",
"OIDCUPDATED":"OIDC configuration updated.", "OIDCUPDATED":"OIDC configuration updated.",
"OIDCCLIENTSECRETREGENERATED":"OIDC client secret generated." "OIDCCLIENTSECRETREGENERATED":"OIDC client secret generated.",
"DELETED":"App deleted."
} }
}, },
"GENDERS": { "GENDERS": {

View File

@@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 467 468" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,0,-492)">
<g id="zitadel-logo-solo-lightdesign" transform="matrix(0.564847,0,0,0.659318,-1282.85,492.925)">
<rect x="2271.15" y="0" width="826.773" height="708.241" style="fill:none;"/>
<g transform="matrix(4.96737,-1.14029,1.331,4.25561,-5923.46,-2258.26)">
<path d="M1493.5,1056.38L1493.5,1037L1496.5,1037L1496.5,1061.62L1426.02,1020.38L1496.5,979.392L1496.5,1004L1493.5,1004L1493.5,984.608L1431.98,1020.39L1493.5,1056.38Z" style="fill:rgb(35,35,35);"/>
</g>
<g transform="matrix(31.0036,0,0,15.0393,-397275,-666.457)">
<g transform="matrix(-0.0429306,-0.282967,0.160219,-0.0758207,12884.5,137.392)">
<path d="M212.517,110L200.392,110L190,92L179.608,110L167.483,110L190,71L212.517,110Z" style="fill:url(#_Linear1);"/>
</g>
<g transform="matrix(0.160219,0.0758207,-0.0429306,0.282967,12878.9,10.8747)">
<path d="M212.517,110L200.392,110L190,92L179.608,110L167.483,110L190,71L212.517,110Z" style="fill:url(#_Linear2);"/>
</g>
<g transform="matrix(-0.117289,0.207146,-0.117289,-0.207146,12943.8,65.7)">
<path d="M212.517,110L200.392,110L190,92L179.608,110L167.483,110L190,71L212.517,110Z" style="fill:url(#_Linear3);"/>
</g>
<g transform="matrix(-0.160219,-0.0758207,0.0429306,-0.282967,12917.4,132.195)">
<path d="M139.622,117L149,142L130.244,142L139.622,117Z" style="fill:url(#_Linear4);"/>
</g>
<g transform="matrix(-0.117289,0.207146,0.117289,0.207146,12897.8,5.87512)">
<path d="M139.622,117L149,142L130.244,142L139.622,117Z" style="fill:url(#_Linear5);"/>
</g>
<g transform="matrix(-0.0429306,-0.282967,-0.160219,0.0758207,12936.8,97.6441)">
<path d="M139.622,117L149,142L130.244,142L139.622,117Z" style="fill:url(#_Linear6);"/>
</g>
</g>
<g transform="matrix(4.96737,-1.14029,1.331,4.25561,-5928.43,-2257.12)">
<circle cx="1496" cy="1004" r="7" style="fill:rgb(35,35,35);"/>
</g>
<g transform="matrix(4.96737,-1.14029,1.331,4.25561,-5884.5,-2116.69)">
<circle cx="1496" cy="1004" r="7" style="fill:rgb(35,35,35);"/>
</g>
<g transform="matrix(4.96737,-1.14029,1.331,4.25561,-5855.22,-2023.06)">
<circle cx="1496" cy="1004" r="7" style="fill:rgb(35,35,35);"/>
</g>
<g transform="matrix(4.96737,-1.14029,1.331,4.25561,-6234.47,-2112.14)">
<circle cx="1496" cy="1004" r="7" style="fill:rgb(35,35,35);"/>
</g>
<g transform="matrix(4.96737,-1.14029,1.331,4.25561,-5957.71,-2350.75)">
<circle cx="1496" cy="1004" r="7" style="fill:rgb(35,35,35);"/>
</g>
<g transform="matrix(4.96737,-1.14029,1.16463,3.72366,-5477.99,-831.33)">
<path d="M1499.26,757.787C1499.26,757.787 1497.37,756.489 1497,755.2C1496.71,754.182 1496.57,750.662 1496.54,750C1496.41,747.303 1499.21,745.644 1499.21,745.644L1490.01,745.835C1490.01,745.835 1493.15,745.713 1493.46,750C1493.51,750.661 1493.23,753.476 1493,755.2C1492.91,756.447 1491.2,757.668 1491.2,757.668L1499.26,757.787Z" style="fill:rgb(35,35,35);"/>
</g>
<g transform="matrix(4.96737,-1.14029,1.16463,3.72366,-5404.79,-597.271)">
<path d="M1495,760L1495,744" style="fill:none;"/>
</g>
<g transform="matrix(4.96737,-1.14029,1.16463,3.72366,-5404.79,-597.271)">
<path d="M1498.27,757.077C1498.27,757.077 1496.71,756.46 1496.65,754.8C1496.65,753.658 1496.64,753.281 1496.65,752.016C1496.62,751.334 1496.59,750.608 1496.65,749.949C1496.78,746.836 1498.5,746.156 1498.5,746.156L1491.46,745.931C1491.46,745.931 1493.37,746.719 1493.65,749.83C1493.71,750.489 1493.69,751.528 1493.65,752.209C1493.64,753.331 1493.64,753.413 1493.65,754.518C1493.68,756.334 1492.58,756.827 1492.58,756.827L1498.27,757.077Z" style="fill:rgb(35,35,35);"/>
</g>
<g transform="matrix(4.96737,-1.14029,1.16463,3.72366,-5770.62,-677.495)">
<path d="M1496.17,759.473L1555.54,720.014" style="fill:none;"/>
</g>
<g transform="matrix(4.96737,-1.14029,1.16463,3.72366,-5770.62,-677.495)">
<path d="M1500.86,762.056C1500.86,762.056 1499.86,760.4 1503.09,757.456C1504.91,755.797 1507.33,754.151 1509.98,752.255C1514.82,748.79 1520.68,744.94 1526.52,741.049C1531.45,737.766 1536.38,734.479 1540.82,731.68C1544.52,729.349 1547.85,727.296 1550.54,725.8C1551.07,725.506 1551.6,725.329 1552.05,725.029C1554.73,723.257 1556.85,724.968 1556.85,724.968L1552.23,716.282C1552.23,716.282 1551.99,719.454 1550,720.997C1549.57,721.333 1549.15,721.741 1548.67,722.12C1546.2,724.053 1542.99,726.344 1539.39,728.867C1535.06,731.898 1530.13,735.166 1525.19,738.438C1519.35,742.314 1513.52,746.234 1508.49,749.329C1505.74,751.023 1503.28,752.577 1501.13,753.598C1497.99,755.086 1495.28,753.617 1495.28,753.617L1500.86,762.056Z" style="fill:rgb(35,35,35);"/>
</g>
<g transform="matrix(4.96737,-1.14029,-1.16463,-3.72366,-3997,4993.28)">
<path d="M1496.17,759.473L1555.54,720.014" style="fill:none;"/>
</g>
<g transform="matrix(4.96737,-1.14029,-1.16463,-3.72366,-3997,4993.28)">
<path d="M1496.1,754.362C1496.1,754.362 1497.2,755.607 1501.13,753.598C1503.25,752.509 1505.74,751.023 1508.49,749.329C1513.52,746.234 1519.35,742.314 1525.19,738.438C1530.13,735.166 1534.94,731.832 1539.27,728.802C1542.87,726.279 1549.36,722.059 1549.81,721.75C1552.75,719.73 1552.18,718.196 1552.18,718.196L1555.28,724.152C1555.28,724.152 1553.77,722.905 1551.37,724.681C1550.93,725.006 1544.52,729.349 1540.82,731.68C1536.38,734.479 1531.45,737.766 1526.52,741.049C1520.68,744.94 1514.82,748.79 1509.98,752.255C1507.33,754.151 1504.89,755.771 1503.09,757.456C1499.47,760.841 1501.26,763.283 1501.26,763.283L1496.1,754.362Z" style="fill:rgb(35,35,35);"/>
</g>
</g>
</g>
<defs>
<linearGradient id="_Linear1" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-41.5984,155.247,-155.247,-41.5984,201.516,76.8392)"><stop offset="0" style="stop-color:rgb(255,143,0);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(254,0,255);stop-opacity:1"/></linearGradient>
<linearGradient id="_Linear2" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(155.247,-41.5984,41.5984,155.247,110.08,195.509)"><stop offset="0" style="stop-color:rgb(255,143,0);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(254,0,255);stop-opacity:1"/></linearGradient>
<linearGradient id="_Linear3" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-113.649,-113.649,113.649,-113.649,258.31,215.618)"><stop offset="0" style="stop-color:rgb(255,143,0);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(254,0,255);stop-opacity:1"/></linearGradient>
<linearGradient id="_Linear4" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-155.247,41.5984,-41.5984,-155.247,220.914,144.546)"><stop offset="0" style="stop-color:rgb(255,143,0);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(254,0,255);stop-opacity:1"/></linearGradient>
<linearGradient id="_Linear5" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-113.649,113.649,113.649,113.649,206.837,124.661)"><stop offset="0" style="stop-color:rgb(255,143,0);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(254,0,255);stop-opacity:1"/></linearGradient>
<linearGradient id="_Linear6" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-41.5984,-155.247,-155.247,41.5984,152.054,262.8)"><stop offset="0" style="stop-color:rgb(255,143,0);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(254,0,255);stop-opacity:1"/></linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 8.5 KiB

View File

@@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 467 467" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g id="zitadel-logo-solo-darkdesign" transform="matrix(0.564847,0,0,0.659318,-1282.85,0)">
<rect x="2271.15" y="0" width="826.773" height="708.241" style="fill:none;"/>
<g transform="matrix(4.96737,-1.14029,1.331,4.25561,-5923.46,-2258.26)">
<path d="M1493.5,1056.38L1493.5,1037L1496.5,1037L1496.5,1061.62L1426.02,1020.38L1496.5,979.392L1496.5,1004L1493.5,1004L1493.5,984.608L1431.98,1020.39L1493.5,1056.38Z" style="fill:white;"/>
</g>
<g transform="matrix(31.0036,0,0,15.0393,-397275,-666.457)">
<g transform="matrix(-0.0429306,-0.282967,0.160219,-0.0758207,12884.5,137.392)">
<path d="M212.517,110L200.392,110L190,92L179.608,110L167.483,110L190,71L212.517,110Z" style="fill:url(#_Linear1);"/>
</g>
<g transform="matrix(0.160219,0.0758207,-0.0429306,0.282967,12878.9,10.8747)">
<path d="M212.517,110L200.392,110L190,92L179.608,110L167.483,110L190,71L212.517,110Z" style="fill:url(#_Linear2);"/>
</g>
<g transform="matrix(-0.117289,0.207146,-0.117289,-0.207146,12943.8,65.7)">
<path d="M212.517,110L200.392,110L190,92L179.608,110L167.483,110L190,71L212.517,110Z" style="fill:url(#_Linear3);"/>
</g>
<g transform="matrix(-0.160219,-0.0758207,0.0429306,-0.282967,12917.4,132.195)">
<path d="M139.622,117L149,142L130.244,142L139.622,117Z" style="fill:url(#_Linear4);"/>
</g>
<g transform="matrix(-0.117289,0.207146,0.117289,0.207146,12897.8,5.87512)">
<path d="M139.622,117L149,142L130.244,142L139.622,117Z" style="fill:url(#_Linear5);"/>
</g>
<g transform="matrix(-0.0429306,-0.282967,-0.160219,0.0758207,12936.8,97.6441)">
<path d="M139.622,117L149,142L130.244,142L139.622,117Z" style="fill:url(#_Linear6);"/>
</g>
</g>
<g transform="matrix(4.96737,-1.14029,1.331,4.25561,-5928.43,-2257.12)">
<circle cx="1496" cy="1004" r="7" style="fill:white;"/>
</g>
<g transform="matrix(4.96737,-1.14029,1.331,4.25561,-5884.5,-2116.69)">
<circle cx="1496" cy="1004" r="7" style="fill:white;"/>
</g>
<g transform="matrix(4.96737,-1.14029,1.331,4.25561,-5855.22,-2023.06)">
<circle cx="1496" cy="1004" r="7" style="fill:white;"/>
</g>
<g transform="matrix(4.96737,-1.14029,1.331,4.25561,-6234.47,-2112.14)">
<circle cx="1496" cy="1004" r="7" style="fill:white;"/>
</g>
<g transform="matrix(4.96737,-1.14029,1.331,4.25561,-5957.71,-2350.75)">
<circle cx="1496" cy="1004" r="7" style="fill:white;"/>
</g>
<g transform="matrix(4.96737,-1.14029,1.16463,3.72366,-5477.99,-831.33)">
<path d="M1499.26,757.787C1499.26,757.787 1497.37,756.489 1497,755.2C1496.71,754.182 1496.57,750.662 1496.54,750C1496.41,747.303 1499.21,745.644 1499.21,745.644L1490.01,745.835C1490.01,745.835 1493.15,745.713 1493.46,750C1493.51,750.661 1493.23,753.476 1493,755.2C1492.91,756.447 1491.2,757.668 1491.2,757.668L1499.26,757.787Z" style="fill:white;"/>
</g>
<g transform="matrix(4.96737,-1.14029,1.16463,3.72366,-5404.79,-597.271)">
<path d="M1495,760L1495,744" style="fill:none;"/>
</g>
<g transform="matrix(4.96737,-1.14029,1.16463,3.72366,-5404.79,-597.271)">
<path d="M1498.27,757.077C1498.27,757.077 1496.71,756.46 1496.65,754.8C1496.65,753.658 1496.64,753.281 1496.65,752.016C1496.62,751.334 1496.59,750.608 1496.65,749.949C1496.78,746.836 1498.5,746.156 1498.5,746.156L1491.46,745.931C1491.46,745.931 1493.37,746.719 1493.65,749.83C1493.71,750.489 1493.69,751.528 1493.65,752.209C1493.64,753.331 1493.64,753.413 1493.65,754.518C1493.68,756.334 1492.58,756.827 1492.58,756.827L1498.27,757.077Z" style="fill:white;"/>
</g>
<g transform="matrix(4.96737,-1.14029,1.16463,3.72366,-5770.62,-677.495)">
<path d="M1496.17,759.473L1555.54,720.014" style="fill:none;"/>
</g>
<g transform="matrix(4.96737,-1.14029,1.16463,3.72366,-5770.62,-677.495)">
<path d="M1500.86,762.056C1500.86,762.056 1499.86,760.4 1503.09,757.456C1504.91,755.797 1507.33,754.151 1509.98,752.255C1514.82,748.79 1520.68,744.94 1526.52,741.049C1531.45,737.766 1536.38,734.479 1540.82,731.68C1544.52,729.349 1547.85,727.296 1550.54,725.8C1551.07,725.506 1551.6,725.329 1552.05,725.029C1554.73,723.257 1556.85,724.968 1556.85,724.968L1552.23,716.282C1552.23,716.282 1551.99,719.454 1550,720.997C1549.57,721.333 1549.15,721.741 1548.67,722.12C1546.2,724.053 1542.99,726.344 1539.39,728.867C1535.06,731.898 1530.13,735.166 1525.19,738.438C1519.35,742.314 1513.52,746.234 1508.49,749.329C1505.74,751.023 1503.28,752.577 1501.13,753.598C1497.99,755.086 1495.28,753.617 1495.28,753.617L1500.86,762.056Z" style="fill:white;"/>
</g>
<g transform="matrix(4.96737,-1.14029,-1.16463,-3.72366,-3997,4993.28)">
<path d="M1496.17,759.473L1555.54,720.014" style="fill:none;"/>
</g>
<g transform="matrix(4.96737,-1.14029,-1.16463,-3.72366,-3997,4993.28)">
<path d="M1496.1,754.362C1496.1,754.362 1497.2,755.607 1501.13,753.598C1503.25,752.509 1505.74,751.023 1508.49,749.329C1513.52,746.234 1519.35,742.314 1525.19,738.438C1530.13,735.166 1534.94,731.832 1539.27,728.802C1542.87,726.279 1549.36,722.059 1549.81,721.75C1552.75,719.73 1552.18,718.196 1552.18,718.196L1555.28,724.152C1555.28,724.152 1553.77,722.905 1551.37,724.681C1550.93,725.006 1544.52,729.349 1540.82,731.68C1536.38,734.479 1531.45,737.766 1526.52,741.049C1520.68,744.94 1514.82,748.79 1509.98,752.255C1507.33,754.151 1504.89,755.771 1503.09,757.456C1499.47,760.841 1501.26,763.283 1501.26,763.283L1496.1,754.362Z" style="fill:white;"/>
</g>
</g>
<defs>
<linearGradient id="_Linear1" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-41.5984,155.247,-155.247,-41.5984,201.516,76.8392)"><stop offset="0" style="stop-color:rgb(255,143,0);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(254,0,255);stop-opacity:1"/></linearGradient>
<linearGradient id="_Linear2" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(155.247,-41.5984,41.5984,155.247,110.08,195.509)"><stop offset="0" style="stop-color:rgb(255,143,0);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(254,0,255);stop-opacity:1"/></linearGradient>
<linearGradient id="_Linear3" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-113.649,-113.649,113.649,-113.649,258.31,215.618)"><stop offset="0" style="stop-color:rgb(255,143,0);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(254,0,255);stop-opacity:1"/></linearGradient>
<linearGradient id="_Linear4" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-155.247,41.5984,-41.5984,-155.247,220.914,144.546)"><stop offset="0" style="stop-color:rgb(255,143,0);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(254,0,255);stop-opacity:1"/></linearGradient>
<linearGradient id="_Linear5" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-113.649,113.649,113.649,113.649,206.837,124.661)"><stop offset="0" style="stop-color:rgb(255,143,0);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(254,0,255);stop-opacity:1"/></linearGradient>
<linearGradient id="_Linear6" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-41.5984,-155.247,-155.247,41.5984,152.054,262.8)"><stop offset="0" style="stop-color:rgb(255,143,0);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(254,0,255);stop-opacity:1"/></linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 8.1 KiB

View File

@@ -5,24 +5,29 @@
@import './styles/link.scss'; @import './styles/link.scss';
@import './styles/sidenav-list'; @import './styles/sidenav-list';
@import 'src/app/modules/avatar/avatar.component'; @import 'src/app/modules/avatar/avatar.component';
@import 'src/app/modules/app-radio/app-type-radio/app-type-radio.component';
@import 'src/app/modules/app-radio/app-auth-method-radio/app-auth-method-radio.component';
@import 'src/app/modules/changes/changes.component'; @import 'src/app/modules/changes/changes.component';
@import 'src/app/modules/info-section/info-section.component'; @import 'src/app/modules/info-section/info-section.component';
@import 'src/app/modules/detail-layout/detail-layout.component'; @import 'src/app/modules/detail-layout/detail-layout.component';
@import 'src/app/pages/projects/owned-projects/owned-project-detail/application-grid/application-grid.component'; @import 'src/app/modules/app-card/app-card.component';
@import 'src/app/pages/users/user-detail/auth-user-detail/theme-setting/theme-card'; @import 'src/app/pages/users/user-detail/auth-user-detail/theme-setting/theme-card';
@import 'src/app/pages/users/user-detail/memberships/memberships.component'; @import 'src/app/pages/users/user-detail/memberships/memberships.component';
@import 'src/app/app.component.scss'; @import 'src/app/app.component.scss';
@import 'src/app/modules/form-field/form-field.component.scss'; @import 'src/app/modules/form-field/form-field.component.scss';
@import 'src/app/modules/label/label.component.scss'; @import 'src/app/modules/label/label.component.scss';
@import 'src/app/modules/meta-layout/meta.scss'; @import 'src/app/modules/meta-layout/meta.scss';
@import 'src/app/modules/onboarding/onboarding.component.scss';
@mixin component-themes($theme) { @mixin component-themes($theme) {
@include avatar-theme($theme); @include avatar-theme($theme);
@include app-type-radio-theme($theme);
@include app-auth-method-radio-theme($theme);
@include card-theme($theme); @include card-theme($theme);
@include table-theme($theme); @include table-theme($theme);
@include detail-layout-theme($theme); @include detail-layout-theme($theme);
@include sidenav-list-theme($theme); @include sidenav-list-theme($theme);
@include application-grid-theme($theme); @include app-card-theme($theme);
@include membership-theme($theme); @include membership-theme($theme);
@include changes-theme($theme); @include changes-theme($theme);
@include theme-card($theme); @include theme-card($theme);
@@ -34,4 +39,5 @@
@include link-theme($theme); @include link-theme($theme);
@include meta-theme($theme); @include meta-theme($theme);
@include info-section-theme($theme); @include info-section-theme($theme);
@include onboarding-theme($theme);
} }

View File

@@ -219,18 +219,21 @@ $custom-typography:
box-shadow: inset 0 0 6px rgba(0, 0, 0, .3); box-shadow: inset 0 0 6px rgba(0, 0, 0, .3);
background-color: #2d2e30; background-color: #2d2e30;
border-radius: 8px; border-radius: 8px;
transition: all .3s cubic-bezier(.645, .045, .355, 1) !important;
} }
::-webkit-scrollbar { ::-webkit-scrollbar {
width: 6px; width: 6px;
height: 6px; height: 6px;
background-color: #2d2e30; background-color: #2d2e30;
transition: all .3s cubic-bezier(.645, .045, .355, 1) !important;
} }
::-webkit-scrollbar-thumb { ::-webkit-scrollbar-thumb {
background-color: #737c8870; background-color: #737c8870;
border-radius: 8px; border-radius: 8px;
cursor: pointer; cursor: pointer;
transition: all .3s cubic-bezier(.645, .045, .355, 1) !important;
} }
.root-header { .root-header {

View File

@@ -16,18 +16,23 @@
box-shadow: inset 1px 0 if($is-dark-theme, #303131, #e3e8ee); box-shadow: inset 1px 0 if($is-dark-theme, #303131, #e3e8ee);
} }
.sidenav {
box-shadow: inset -1px 0 if($is-dark-theme, #303131, #e3e8ee);
transition: all .3s cubic-bezier(.645, .045, .355, 1) !important;
}
.nav-item { .nav-item {
color: mat-color($foreground, text) !important; color: mat-color($foreground, text) !important;
&:hover { &:hover {
background-color: $sec-dark; background-color: if($is-dark-theme, $sec-dark, rgb(84 105 212 / 6%));
border-top-right-radius: 1.5rem; border-top-right-radius: 1.5rem;
border-bottom-right-radius: 1.5rem; border-bottom-right-radius: 1.5rem;
} }
&.active { &.active {
color: $primary-color !important; color: $primary-color !important;
background-color: rgba($color: $primary-color, $alpha: .1) !important; background-color: if($is-dark-theme, rgba($color: $primary-color, $alpha: .1), rgb(84 105 212 / 6%)) !important;
} }
.c_label { .c_label {
@@ -54,7 +59,16 @@
.root-header { .root-header {
box-shadow: inset 0 -1px #e3e8ee; box-shadow: inset 0 -1px #e3e8ee;
background-color: $primary-dark !important; background-color: $primary-dark !important;
transition: background-color .3s cubic-bezier(.645, .045, .355, 1); transition: all .3s cubic-bezier(.645, .045, .355, 1);
.slash {
color: if($is-dark-theme, #525454, #d1d5d9);
}
.org-button {
border: 1px solid if($is-dark-theme, #303131, #e3e8ee);
transition: all .3s cubic-bezier(.645, .045, .355, 1) !important;
}
} }
.admin-line { .admin-line {
@@ -63,7 +77,7 @@
align-items: center; align-items: center;
bottom: 0; bottom: 0;
left: 0; left: 0;
right: calc(100vw - 300px); right: calc(100vw - 280px);
background-color: $primary-color; background-color: $primary-color;
color: white; color: white;
z-index: 1; z-index: 1;

View File

@@ -64,7 +64,8 @@
} }
} }
.mat-checkbox { td .mat-checkbox,
th .mat-checkbox {
margin-left: 1rem; margin-left: 1rem;
} }

6
go.mod
View File

@@ -16,7 +16,7 @@ require (
github.com/allegro/bigcache v1.2.1 github.com/allegro/bigcache v1.2.1
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc
github.com/caos/logging v0.0.2 github.com/caos/logging v0.0.2
github.com/caos/oidc v0.13.2 github.com/caos/oidc v0.14.0
github.com/caos/orbos v1.5.14-0.20210205131708-6dc812182dc0 github.com/caos/orbos v1.5.14-0.20210205131708-6dc812182dc0
github.com/cockroachdb/cockroach-go/v2 v2.1.0 github.com/cockroachdb/cockroach-go/v2 v2.1.0
github.com/duo-labs/webauthn v0.0.0-20200714211715-1daaee874e43 github.com/duo-labs/webauthn v0.0.0-20200714211715-1daaee874e43
@@ -56,7 +56,7 @@ require (
github.com/rs/cors v1.7.0 github.com/rs/cors v1.7.0
github.com/sony/sonyflake v1.0.0 github.com/sony/sonyflake v1.0.0
github.com/spf13/cobra v0.0.7 github.com/spf13/cobra v0.0.7
github.com/stretchr/testify v1.6.1 github.com/stretchr/testify v1.7.0
github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2 // indirect github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2 // indirect
github.com/ttacon/libphonenumber v1.1.0 github.com/ttacon/libphonenumber v1.1.0
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.13.0 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.13.0
@@ -69,7 +69,7 @@ require (
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102 // indirect golang.org/x/net v0.0.0-20201031054903-ff519b6c9102 // indirect
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 // indirect golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 // indirect
golang.org/x/text v0.3.4 golang.org/x/text v0.3.5
golang.org/x/tools v0.0.0-20201103235415-b653051172e4 golang.org/x/tools v0.0.0-20201103235415-b653051172e4
google.golang.org/api v0.34.0 google.golang.org/api v0.34.0
google.golang.org/appengine v1.6.7 // indirect google.golang.org/appengine v1.6.7 // indirect

53
go.sum
View File

@@ -108,6 +108,7 @@ github.com/allegro/bigcache v1.2.1 h1:hg1sY1raCwic3Vnsvje6TT7/pnZba83LeFck5NrFKS
github.com/allegro/bigcache v1.2.1/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/allegro/bigcache v1.2.1/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
@@ -116,6 +117,7 @@ github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hC
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
@@ -124,6 +126,7 @@ github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQ
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.31.12/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= github.com/aws/aws-sdk-go v1.31.12/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
github.com/benbjohnson/clock v1.0.3 h1:vkLuvpK4fmtSCuo60+yC63p7y0BmQ8gm5ZXGuBCJyXg=
github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
@@ -137,12 +140,8 @@ github.com/caos/logging v0.0.0-20191210002624-b3260f690a6a/go.mod h1:9LKiDE2ChuG
github.com/caos/logging v0.0.2 h1:ebg5C/HN0ludYR+WkvnFjwSExF4wvyiWPyWGcKMYsoo= github.com/caos/logging v0.0.2 h1:ebg5C/HN0ludYR+WkvnFjwSExF4wvyiWPyWGcKMYsoo=
github.com/caos/logging v0.0.2/go.mod h1:9LKiDE2ChuGv6CHYif/kiugrfEXu9AwDiFWSreX7Wp0= github.com/caos/logging v0.0.2/go.mod h1:9LKiDE2ChuGv6CHYif/kiugrfEXu9AwDiFWSreX7Wp0=
github.com/caos/oidc v0.6.2/go.mod h1:ozoi3b+aY33gzdvjz4w90VZShIHGsmDa0goruuV0arQ= github.com/caos/oidc v0.6.2/go.mod h1:ozoi3b+aY33gzdvjz4w90VZShIHGsmDa0goruuV0arQ=
github.com/caos/oidc v0.13.2 h1:52oP3KB1UrZuwraBTLuwM9ItRIhJQMYOm1J5uQ0sYXw= github.com/caos/oidc v0.14.0 h1:l7mTqYDpqNRZF9Vwzq5KAQd1wQCThdceL5HpsEMGoao=
github.com/caos/oidc v0.13.2/go.mod h1:dLvfYUiAt9ORfl77L/KkcWuR/N0ll8Ry1nD2ERsamDY= github.com/caos/oidc v0.14.0/go.mod h1:CPsubVrA110OyLnCKwVZjTdsAVwq67DTbYIvux7UgbY=
github.com/caos/orbos v1.5.14-0.20210128140136-842933949472 h1:iti4tAKxBknjJkQcDKWaxlj9Jbng5kz5TpQzzyda49o=
github.com/caos/orbos v1.5.14-0.20210128140136-842933949472/go.mod h1:ZLxNgPuYIlSvr80trezGGUIXng9gY2hHEdky/m0B/P0=
github.com/caos/orbos v1.5.14-0.20210202122121-ad32524ffc73 h1:usYmCT11HvwxBCk1+DSCmEU6CVYhzY8jHaQHSJMrxlg=
github.com/caos/orbos v1.5.14-0.20210202122121-ad32524ffc73/go.mod h1:ZLxNgPuYIlSvr80trezGGUIXng9gY2hHEdky/m0B/P0=
github.com/caos/orbos v1.5.14-0.20210205131708-6dc812182dc0 h1:N+KYBwuQO3QPr/nTUaNwjAetjp3NU4MP8Nv9Iue53UE= github.com/caos/orbos v1.5.14-0.20210205131708-6dc812182dc0 h1:N+KYBwuQO3QPr/nTUaNwjAetjp3NU4MP8Nv9Iue53UE=
github.com/caos/orbos v1.5.14-0.20210205131708-6dc812182dc0/go.mod h1:ZLxNgPuYIlSvr80trezGGUIXng9gY2hHEdky/m0B/P0= github.com/caos/orbos v1.5.14-0.20210205131708-6dc812182dc0/go.mod h1:ZLxNgPuYIlSvr80trezGGUIXng9gY2hHEdky/m0B/P0=
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
@@ -154,9 +153,11 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw=
github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
@@ -186,13 +187,17 @@ github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfc
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.7 h1:6pwm8kMQKCmgUg0ZHTm5+/YvRK0s3THD/28+T6/kk4A=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE= github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE=
github.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9rTHJQ=
github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ=
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM=
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
@@ -212,6 +217,7 @@ github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5m
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc=
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
@@ -224,23 +230,28 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
github.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A= github.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y=
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
github.com/evanphx/json-patch v4.2.0+incompatible h1:fUDGZCv/7iAN7u0puUVhvKCcsR6vRfwrJatElLBEf0I=
github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4=
github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ=
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fxamacker/cbor/v2 v2.2.0 h1:6eXqdDDe588rSYAi1HfZKbx6YYQO4mxQ9eC6xYpU/JQ= github.com/fxamacker/cbor/v2 v2.2.0 h1:6eXqdDDe588rSYAi1HfZKbx6YYQO4mxQ9eC6xYpU/JQ=
github.com/fxamacker/cbor/v2 v2.2.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= github.com/fxamacker/cbor/v2 v2.2.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo=
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
@@ -298,6 +309,7 @@ github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+
github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA=
github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
@@ -308,6 +320,7 @@ github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
@@ -367,8 +380,10 @@ github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.1.0 h1:wCKgOCHuUEVfsaQLpPSJb7VdYCdTVZQAuOdYm1yc/60=
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
@@ -383,6 +398,8 @@ github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM= github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
@@ -390,6 +407,7 @@ github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsC
github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
github.com/googleapis/gnostic v0.3.1 h1:WeAefnSUHlBb0iJKwxFDZdbfGwkd7xRNuV+IpXMJhYk= github.com/googleapis/gnostic v0.3.1 h1:WeAefnSUHlBb0iJKwxFDZdbfGwkd7xRNuV+IpXMJhYk=
github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU=
github.com/googleinterns/cloud-operations-api-mock v0.0.0-20200709193332-a1e58c29bdd3 h1:eHv/jVY/JNop1xg2J9cBb4EzyMpWZoNCP1BslSAIkOI=
github.com/googleinterns/cloud-operations-api-mock v0.0.0-20200709193332-a1e58c29bdd3/go.mod h1:h/KNeRx7oYU4SpA4SoY7W2/NxDKEEVuwA6j9A27L4OI= github.com/googleinterns/cloud-operations-api-mock v0.0.0-20200709193332-a1e58c29bdd3/go.mod h1:h/KNeRx7oYU4SpA4SoY7W2/NxDKEEVuwA6j9A27L4OI=
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
@@ -442,7 +460,9 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174 h1:WlZsjVhE8Af9IcZDGgJGQpNflI3+MJSBhsgT5PCtzBQ=
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A= github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw= github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw=
github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
@@ -455,6 +475,7 @@ github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA=
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/inconshreveable/log15 v0.0.0-20200109203555-b30bc20e4fd1 h1:KUDFlmBg2buRWNzIcwLlKvfcnujcHQRQ1As1LoaCLAM= github.com/inconshreveable/log15 v0.0.0-20200109203555-b30bc20e4fd1 h1:KUDFlmBg2buRWNzIcwLlKvfcnujcHQRQ1As1LoaCLAM=
github.com/inconshreveable/log15 v0.0.0-20200109203555-b30bc20e4fd1/go.mod h1:cOaXtrgN4ScfRrD9Bre7U1thNq5RtJ8ZoP4iXVGRj6o= github.com/inconshreveable/log15 v0.0.0-20200109203555-b30bc20e4fd1/go.mod h1:cOaXtrgN4ScfRrD9Bre7U1thNq5RtJ8ZoP4iXVGRj6o=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
@@ -510,6 +531,7 @@ github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBef
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jinzhu/now v1.1.1 h1:g39TucaRWyV3dwDO++eEc6qf8TVIQ/Da48WmqjZ3i7E=
github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
@@ -523,6 +545,7 @@ github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a h1:FaWFmfWdAUKbSCtOU2QjDaorUexogfaMgbipgYATUMU= github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a h1:FaWFmfWdAUKbSCtOU2QjDaorUexogfaMgbipgYATUMU=
@@ -553,8 +576,11 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.4/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.4/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
github.com/kr/pty v1.1.8 h1:AkaSdXYQOWeaO3neb8EM634ahkXXe3jYbVh/F9lq+GI=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/landoop/tableprinter v0.0.0-20200805134727-ea32388e35c1/go.mod h1:f0X1c0za3TbET/rl5ThtCSel0+G3/yZ8iuU9BxnyVK0= github.com/landoop/tableprinter v0.0.0-20200805134727-ea32388e35c1/go.mod h1:f0X1c0za3TbET/rl5ThtCSel0+G3/yZ8iuU9BxnyVK0=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
@@ -602,6 +628,7 @@ github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus= github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
@@ -644,6 +671,7 @@ github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxzi
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/nicksnyder/go-i18n/v2 v2.1.1 h1:ATCOanRDlrfKVB4WHAdJnLEqZtDmKYsweqsOUYflnBU= github.com/nicksnyder/go-i18n/v2 v2.1.1 h1:ATCOanRDlrfKVB4WHAdJnLEqZtDmKYsweqsOUYflnBU=
github.com/nicksnyder/go-i18n/v2 v2.1.1/go.mod h1:d++QJC9ZVf7pa48qrsRWhMJ5pSHIPmS3OLqK1niyLxs= github.com/nicksnyder/go-i18n/v2 v2.1.1/go.mod h1:d++QJC9ZVf7pa48qrsRWhMJ5pSHIPmS3OLqK1niyLxs=
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= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
@@ -653,9 +681,11 @@ github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FW
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw=
github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
@@ -792,6 +822,8 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
@@ -908,6 +940,7 @@ golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHl
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
@@ -1053,6 +1086,8 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -1154,6 +1189,7 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
@@ -1231,9 +1267,11 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
@@ -1246,9 +1284,11 @@ gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w
gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/src-d/go-billy.v4 v4.3.2 h1:0SQA1pRztfTFx2miS8sA97XvooFeNOmvUenF4o0EcVg= gopkg.in/src-d/go-billy.v4 v4.3.2 h1:0SQA1pRztfTFx2miS8sA97XvooFeNOmvUenF4o0EcVg=
gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98= gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98=
gopkg.in/src-d/go-git-fixtures.v3 v3.5.0 h1:ivZFOIltbce2Mo8IjzUHAFoq/IylO9WHhNOAJK+LsJg=
gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g=
gopkg.in/src-d/go-git.v4 v4.13.1 h1:SRtFyV8Kxc0UP7aCHcijOMQGPxHSmMOPrzulQWolkYE= gopkg.in/src-d/go-git.v4 v4.13.1 h1:SRtFyV8Kxc0UP7aCHcijOMQGPxHSmMOPrzulQWolkYE=
gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8= gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
@@ -1301,6 +1341,7 @@ k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUc
k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6 h1:Oh3Mzx5pJ+yIumsAD0MOECPVeXsVot0UkiaCGVyfGQY=
k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E=
k8s.io/kubectl v0.18.3/go.mod h1:k/EpvXBDgEsHBzWr0A44l9+ArvYi3txBBnzXBjQasUQ= k8s.io/kubectl v0.18.3/go.mod h1:k/EpvXBDgEsHBzWr0A44l9+ArvYi3txBBnzXBjQasUQ=
k8s.io/metrics v0.18.3/go.mod h1:TkuJE3ezDZ1ym8pYkZoEzJB7HDiFE7qxl+EmExEBoPA= k8s.io/metrics v0.18.3/go.mod h1:TkuJE3ezDZ1ym8pYkZoEzJB7HDiFE7qxl+EmExEBoPA=

View File

@@ -37,6 +37,27 @@ type Grant struct {
Roles []string Roles []string
} }
type Memberships []*Membership
type Membership struct {
MemberType MemberType
AggregateID string
//ObjectID differs from aggregate id if obejct is sub of an aggregate
ObjectID string
Roles []string
}
type MemberType int32
const (
MemberTypeUnspecified MemberType = iota
MemberTypeOrganisation
MemberTypeProject
MemberTypeProjectGrant
MemberTypeIam
)
func VerifyTokenAndCreateCtxData(ctx context.Context, token, orgID string, t *TokenVerifier, method string) (_ CtxData, err error) { func VerifyTokenAndCreateCtxData(ctx context.Context, token, orgID string, t *TokenVerifier, method string) (_ CtxData, err error) {
ctx, span := tracing.NewSpan(ctx) ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }() defer func() { span.EndWithError(err) }()

View File

@@ -2,7 +2,6 @@ package authz
import ( import (
"context" "context"
"github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/telemetry/tracing" "github.com/caos/zitadel/internal/telemetry/tracing"
) )
@@ -16,41 +15,43 @@ func getUserMethodPermissions(ctx context.Context, t *TokenVerifier, requiredPer
} }
ctx = context.WithValue(ctx, dataKey, ctxData) ctx = context.WithValue(ctx, dataKey, ctxData)
grant, err := t.ResolveGrant(ctx) memberships, err := t.SearchMyMemberships(ctx)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
if grant == nil { if len(memberships) == 0 {
return requestedPermissions, nil, nil return requestedPermissions, nil, nil
} }
requestedPermissions, allPermissions = mapGrantToPermissions(requiredPerm, grant, authConfig) requestedPermissions, allPermissions = mapMembershipsToPermissions(requiredPerm, memberships, authConfig)
return requestedPermissions, allPermissions, nil return requestedPermissions, allPermissions, nil
} }
func mapGrantToPermissions(requiredPerm string, grant *Grant, authConfig Config) (requestPermissions, allPermissions []string) { func mapMembershipsToPermissions(requiredPerm string, memberships []*Membership, authConfig Config) (requestPermissions, allPermissions []string) {
requestPermissions = make([]string, 0) requestPermissions = make([]string, 0)
allPermissions = make([]string, 0) allPermissions = make([]string, 0)
for _, role := range grant.Roles { for _, membership := range memberships {
requestPermissions, allPermissions = mapRoleToPerm(requiredPerm, role, authConfig, requestPermissions, allPermissions) requestPermissions, allPermissions = mapMembershipToPerm(requiredPerm, membership, authConfig, requestPermissions, allPermissions)
} }
return requestPermissions, allPermissions return requestPermissions, allPermissions
} }
func mapRoleToPerm(requiredPerm, actualRole string, authConfig Config, requestPermissions, allPermissions []string) ([]string, []string) { func mapMembershipToPerm(requiredPerm string, membership *Membership, authConfig Config, requestPermissions, allPermissions []string) ([]string, []string) {
roleName, roleContextID := SplitPermission(actualRole) roleNames, roleContextID := roleWithContext(membership)
perms := authConfig.getPermissionsFromRole(roleName) for _, roleName := range roleNames {
perms := authConfig.getPermissionsFromRole(roleName)
for _, p := range perms { for _, p := range perms {
permWithCtx := addRoleContextIDToPerm(p, roleContextID) permWithCtx := addRoleContextIDToPerm(p, roleContextID)
if !ExistsPerm(allPermissions, permWithCtx) { if !ExistsPerm(allPermissions, permWithCtx) {
allPermissions = append(allPermissions, permWithCtx) allPermissions = append(allPermissions, permWithCtx)
} }
p, _ = SplitPermission(p) p, _ = SplitPermission(p)
if p == requiredPerm { if p == requiredPerm {
if !ExistsPerm(requestPermissions, permWithCtx) { if !ExistsPerm(requestPermissions, permWithCtx) {
requestPermissions = append(requestPermissions, permWithCtx) requestPermissions = append(requestPermissions, permWithCtx)
}
} }
} }
} }
@@ -72,3 +73,10 @@ func ExistsPerm(existingPermissions []string, perm string) bool {
} }
return false return false
} }
func roleWithContext(membership *Membership) (roles []string, ctxID string) {
if membership.MemberType == MemberTypeProject || membership.MemberType == MemberTypeProjectGrant {
return membership.Roles, membership.ObjectID
}
return membership.Roles, ""
}

View File

@@ -12,15 +12,14 @@ func getTestCtx(userID, orgID string) context.Context {
} }
type testVerifier struct { type testVerifier struct {
grant *Grant memberships []*Membership
} }
func (v *testVerifier) VerifyAccessToken(ctx context.Context, token, clientID string) (string, string, string, string, error) { func (v *testVerifier) VerifyAccessToken(ctx context.Context, token, clientID string) (string, string, string, string, error) {
return "userID", "agentID", "de", "orgID", nil return "userID", "agentID", "de", "orgID", nil
} }
func (v *testVerifier) SearchMyMemberships(ctx context.Context) ([]*Membership, error) {
func (v *testVerifier) ResolveGrants(ctx context.Context) (*Grant, error) { return v.memberships, nil
return v.grant, nil
} }
func (v *testVerifier) ProjectIDAndOriginsByClientID(ctx context.Context, clientID string) (string, []string, error) { func (v *testVerifier) ProjectIDAndOriginsByClientID(ctx context.Context, clientID string) (string, []string, error) {
@@ -65,8 +64,10 @@ func Test_GetUserMethodPermissions(t *testing.T) {
name: "Empty Context", name: "Empty Context",
args: args{ args: args{
ctxData: CtxData{}, ctxData: CtxData{},
verifier: Start(&testVerifier{grant: &Grant{ verifier: Start(&testVerifier{memberships: []*Membership{
Roles: []string{"ORG_OWNER"}, {
Roles: []string{"ORG_OWNER"},
},
}}), }}),
requiredPerm: "project.read", requiredPerm: "project.read",
authConfig: Config{ authConfig: Config{
@@ -90,7 +91,7 @@ func Test_GetUserMethodPermissions(t *testing.T) {
name: "No Grants", name: "No Grants",
args: args{ args: args{
ctxData: CtxData{}, ctxData: CtxData{},
verifier: Start(&testVerifier{grant: &Grant{}}), verifier: Start(&testVerifier{memberships: []*Membership{}}),
requiredPerm: "project.read", requiredPerm: "project.read",
authConfig: Config{ authConfig: Config{
RolePermissionMappings: []RoleMapping{ RolePermissionMappings: []RoleMapping{
@@ -111,8 +112,13 @@ func Test_GetUserMethodPermissions(t *testing.T) {
name: "Get Permissions", name: "Get Permissions",
args: args{ args: args{
ctxData: CtxData{UserID: "userID", OrgID: "orgID"}, ctxData: CtxData{UserID: "userID", OrgID: "orgID"},
verifier: Start(&testVerifier{grant: &Grant{ verifier: Start(&testVerifier{memberships: []*Membership{
Roles: []string{"IAM_OWNER"}, {
AggregateID: "IAM",
ObjectID: "IAM",
MemberType: MemberTypeIam,
Roles: []string{"IAM_OWNER"},
},
}}), }}),
requiredPerm: "project.read", requiredPerm: "project.read",
authConfig: Config{ authConfig: Config{
@@ -150,10 +156,10 @@ func Test_GetUserMethodPermissions(t *testing.T) {
} }
} }
func Test_MapGrantsToPermissions(t *testing.T) { func Test_MapMembershipToPermissions(t *testing.T) {
type args struct { type args struct {
requiredPerm string requiredPerm string
grant *Grant membership []*Membership
authConfig Config authConfig Config
} }
tests := []struct { tests := []struct {
@@ -166,7 +172,14 @@ func Test_MapGrantsToPermissions(t *testing.T) {
name: "One Role existing perm", name: "One Role existing perm",
args: args{ args: args{
requiredPerm: "project.read", requiredPerm: "project.read",
grant: &Grant{Roles: []string{"ORG_OWNER"}}, membership: []*Membership{
{
AggregateID: "1",
ObjectID: "1",
MemberType: MemberTypeOrganisation,
Roles: []string{"ORG_OWNER"},
},
},
authConfig: Config{ authConfig: Config{
RolePermissionMappings: []RoleMapping{ RolePermissionMappings: []RoleMapping{
{ {
@@ -187,7 +200,14 @@ func Test_MapGrantsToPermissions(t *testing.T) {
name: "One Role not existing perm", name: "One Role not existing perm",
args: args{ args: args{
requiredPerm: "project.write", requiredPerm: "project.write",
grant: &Grant{Roles: []string{"ORG_OWNER"}}, membership: []*Membership{
{
AggregateID: "1",
ObjectID: "1",
MemberType: MemberTypeOrganisation,
Roles: []string{"ORG_OWNER"},
},
},
authConfig: Config{ authConfig: Config{
RolePermissionMappings: []RoleMapping{ RolePermissionMappings: []RoleMapping{
{ {
@@ -208,7 +228,20 @@ func Test_MapGrantsToPermissions(t *testing.T) {
name: "Multiple Roles one existing", name: "Multiple Roles one existing",
args: args{ args: args{
requiredPerm: "project.read", requiredPerm: "project.read",
grant: &Grant{Roles: []string{"ORG_OWNER", "IAM_OWNER"}}, membership: []*Membership{
{
AggregateID: "1",
ObjectID: "1",
MemberType: MemberTypeOrganisation,
Roles: []string{"ORG_OWNER"},
},
{
AggregateID: "IAM",
ObjectID: "IAM",
MemberType: MemberTypeIam,
Roles: []string{"IAM_OWNER"},
},
},
authConfig: Config{ authConfig: Config{
RolePermissionMappings: []RoleMapping{ RolePermissionMappings: []RoleMapping{
{ {
@@ -229,7 +262,20 @@ func Test_MapGrantsToPermissions(t *testing.T) {
name: "Multiple Roles, global and specific", name: "Multiple Roles, global and specific",
args: args{ args: args{
requiredPerm: "project.read", requiredPerm: "project.read",
grant: &Grant{Roles: []string{"ORG_OWNER", "PROJECT_OWNER:1"}}, membership: []*Membership{
{
AggregateID: "2",
ObjectID: "2",
MemberType: MemberTypeOrganisation,
Roles: []string{"ORG_OWNER"},
},
{
AggregateID: "1",
ObjectID: "1",
MemberType: MemberTypeProject,
Roles: []string{"PROJECT_OWNER"},
},
},
authConfig: Config{ authConfig: Config{
RolePermissionMappings: []RoleMapping{ RolePermissionMappings: []RoleMapping{
{ {
@@ -249,7 +295,7 @@ func Test_MapGrantsToPermissions(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
requestPerms, allPerms := mapGrantToPermissions(tt.args.requiredPerm, tt.args.grant, tt.args.authConfig) requestPerms, allPerms := mapMembershipsToPermissions(tt.args.requiredPerm, tt.args.membership, tt.args.authConfig)
if !equalStringArray(requestPerms, tt.requestPerms) { if !equalStringArray(requestPerms, tt.requestPerms) {
t.Errorf("got wrong requestPerms, expecting: %v, actual: %v ", tt.requestPerms, requestPerms) t.Errorf("got wrong requestPerms, expecting: %v, actual: %v ", tt.requestPerms, requestPerms)
} }
@@ -260,10 +306,10 @@ func Test_MapGrantsToPermissions(t *testing.T) {
} }
} }
func Test_MapRoleToPerm(t *testing.T) { func Test_MapMembershipToPerm(t *testing.T) {
type args struct { type args struct {
requiredPerm string requiredPerm string
actualRole string membership *Membership
authConfig Config authConfig Config
requestPerms []string requestPerms []string
allPerms []string allPerms []string
@@ -278,7 +324,12 @@ func Test_MapRoleToPerm(t *testing.T) {
name: "first perm without context id", name: "first perm without context id",
args: args{ args: args{
requiredPerm: "project.read", requiredPerm: "project.read",
actualRole: "ORG_OWNER", membership: &Membership{
AggregateID: "Org",
ObjectID: "Org",
MemberType: MemberTypeOrganisation,
Roles: []string{"ORG_OWNER"},
},
authConfig: Config{ authConfig: Config{
RolePermissionMappings: []RoleMapping{ RolePermissionMappings: []RoleMapping{
{ {
@@ -301,7 +352,12 @@ func Test_MapRoleToPerm(t *testing.T) {
name: "existing perm without context id", name: "existing perm without context id",
args: args{ args: args{
requiredPerm: "project.read", requiredPerm: "project.read",
actualRole: "ORG_OWNER", membership: &Membership{
AggregateID: "Org",
ObjectID: "Org",
MemberType: MemberTypeOrganisation,
Roles: []string{"ORG_OWNER"},
},
authConfig: Config{ authConfig: Config{
RolePermissionMappings: []RoleMapping{ RolePermissionMappings: []RoleMapping{
{ {
@@ -324,7 +380,12 @@ func Test_MapRoleToPerm(t *testing.T) {
name: "first perm with context id", name: "first perm with context id",
args: args{ args: args{
requiredPerm: "project.read", requiredPerm: "project.read",
actualRole: "PROJECT_OWNER:1", membership: &Membership{
AggregateID: "1",
ObjectID: "1",
MemberType: MemberTypeProject,
Roles: []string{"PROJECT_OWNER"},
},
authConfig: Config{ authConfig: Config{
RolePermissionMappings: []RoleMapping{ RolePermissionMappings: []RoleMapping{
{ {
@@ -347,7 +408,12 @@ func Test_MapRoleToPerm(t *testing.T) {
name: "perm with context id, existing global", name: "perm with context id, existing global",
args: args{ args: args{
requiredPerm: "project.read", requiredPerm: "project.read",
actualRole: "PROJECT_OWNER:1", membership: &Membership{
AggregateID: "1",
ObjectID: "1",
MemberType: MemberTypeProject,
Roles: []string{"PROJECT_OWNER"},
},
authConfig: Config{ authConfig: Config{
RolePermissionMappings: []RoleMapping{ RolePermissionMappings: []RoleMapping{
{ {
@@ -369,7 +435,7 @@ func Test_MapRoleToPerm(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
requestPerms, allPerms := mapRoleToPerm(tt.args.requiredPerm, tt.args.actualRole, tt.args.authConfig, tt.args.requestPerms, tt.args.allPerms) requestPerms, allPerms := mapMembershipToPerm(tt.args.requiredPerm, tt.args.membership, tt.args.authConfig, tt.args.requestPerms, tt.args.allPerms)
if !equalStringArray(requestPerms, tt.requestPerms) { if !equalStringArray(requestPerms, tt.requestPerms) {
t.Errorf("got wrong requestPerms, expecting: %v, actual: %v ", tt.requestPerms, requestPerms) t.Errorf("got wrong requestPerms, expecting: %v, actual: %v ", tt.requestPerms, requestPerms)
} }

View File

@@ -22,7 +22,7 @@ type TokenVerifier struct {
type authZRepo interface { type authZRepo interface {
VerifyAccessToken(ctx context.Context, token, clientID string) (userID, agentID, prefLang, resourceOwner string, err error) VerifyAccessToken(ctx context.Context, token, clientID string) (userID, agentID, prefLang, resourceOwner string, err error)
VerifierClientID(ctx context.Context, name string) (clientID string, err error) VerifierClientID(ctx context.Context, name string) (clientID string, err error)
ResolveGrants(ctx context.Context) (grant *Grant, err error) SearchMyMemberships(ctx context.Context) ([]*Membership, error)
ProjectIDAndOriginsByClientID(ctx context.Context, clientID string) (projectID string, origins []string, err error) ProjectIDAndOriginsByClientID(ctx context.Context, clientID string) (projectID string, origins []string, err error)
ExistsOrg(ctx context.Context, orgID string) error ExistsOrg(ctx context.Context, orgID string) error
} }
@@ -86,11 +86,10 @@ func (v *TokenVerifier) clientIDFromMethod(ctx context.Context, method string) (
v.clients.Store(prefix, c) v.clients.Store(prefix, c)
return c.id, nil return c.id, nil
} }
func (v *TokenVerifier) SearchMyMemberships(ctx context.Context) (_ []*Membership, err error) {
func (v *TokenVerifier) ResolveGrant(ctx context.Context) (_ *Grant, err error) {
ctx, span := tracing.NewSpan(ctx) ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }() defer func() { span.EndWithError(err) }()
return v.authZRepo.ResolveGrants(ctx) return v.authZRepo.SearchMyMemberships(ctx)
} }
func (v *TokenVerifier) ProjectIDAndOriginsByClientID(ctx context.Context, clientID string) (_ string, _ []string, err error) { func (v *TokenVerifier) ProjectIDAndOriginsByClientID(ctx context.Context, clientID string) (_ string, _ []string, err error) {

View File

@@ -43,7 +43,7 @@ func Test_VerifyAccessToken(t *testing.T) {
ctx: context.Background(), ctx: context.Background(),
token: "Bearer AUTH", token: "Bearer AUTH",
verifier: &TokenVerifier{ verifier: &TokenVerifier{
authZRepo: &testVerifier{grant: &Grant{}}, authZRepo: &testVerifier{memberships: []*Membership{}},
clients: func() sync.Map { clients: func() sync.Map {
m := sync.Map{} m := sync.Map{}
m.Store("service", &client{name: "name"}) m.Store("service", &client{name: "name"})

View File

@@ -229,3 +229,13 @@ func (s *Server) GetMyUserChanges(ctx context.Context, request *auth.ChangesRequ
} }
return userChangesToResponse(changes, request.GetSequenceOffset(), request.GetLimit()), nil return userChangesToResponse(changes, request.GetSequenceOffset(), request.GetLimit()), nil
} }
func (s *Server) SearchMyUserMemberships(ctx context.Context, in *auth.UserMembershipSearchRequest) (*auth.UserMembershipSearchResponse, error) {
request := userMembershipSearchRequestsToModel(in)
request.AppendUserIDQuery(authz.GetCtxData(ctx).UserID)
response, err := s.repo.SearchMyUserMemberships(ctx, request)
if err != nil {
return nil, err
}
return userMembershipSearchResponseFromModel(response), nil
}

View File

@@ -3,7 +3,6 @@ package auth
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"github.com/caos/logging" "github.com/caos/logging"
"github.com/golang/protobuf/ptypes" "github.com/golang/protobuf/ptypes"
"golang.org/x/text/language" "golang.org/x/text/language"
@@ -462,3 +461,93 @@ func ctxToObjectRoot(ctx context.Context) models.ObjectRoot {
ResourceOwner: ctxData.ResourceOwner, ResourceOwner: ctxData.ResourceOwner,
} }
} }
func userMembershipSearchResponseFromModel(response *usr_model.UserMembershipSearchResponse) *auth.UserMembershipSearchResponse {
timestamp, err := ptypes.TimestampProto(response.Timestamp)
logging.Log("GRPC-Hs8jd").OnError(err).Debug("unable to parse timestamp")
return &auth.UserMembershipSearchResponse{
Offset: response.Offset,
Limit: response.Limit,
TotalResult: response.TotalResult,
Result: userMembershipViewsFromModel(response.Result),
ProcessedSequence: response.Sequence,
ViewTimestamp: timestamp,
}
}
func userMembershipViewsFromModel(memberships []*usr_model.UserMembershipView) []*auth.UserMembershipView {
converted := make([]*auth.UserMembershipView, len(memberships))
for i, membership := range memberships {
converted[i] = userMembershipViewFromModel(membership)
}
return converted
}
func userMembershipViewFromModel(membership *usr_model.UserMembershipView) *auth.UserMembershipView {
creationDate, err := ptypes.TimestampProto(membership.CreationDate)
logging.Log("GRPC-Msnu8").OnError(err).Debug("unable to parse timestamp")
changeDate, err := ptypes.TimestampProto(membership.ChangeDate)
logging.Log("GRPC-Slco9").OnError(err).Debug("unable to parse timestamp")
return &auth.UserMembershipView{
UserId: membership.UserID,
AggregateId: membership.AggregateID,
ObjectId: membership.ObjectID,
MemberType: memberTypeFromModel(membership.MemberType),
DisplayName: membership.DisplayName,
Roles: membership.Roles,
CreationDate: creationDate,
ChangeDate: changeDate,
Sequence: membership.Sequence,
ResourceOwner: membership.ResourceOwner,
}
}
func userMembershipSearchRequestsToModel(request *auth.UserMembershipSearchRequest) *usr_model.UserMembershipSearchRequest {
return &usr_model.UserMembershipSearchRequest{
Offset: request.Offset,
Limit: request.Limit,
Queries: userMembershipSearchQueriesToModel(request.Queries),
}
}
func userMembershipSearchQueriesToModel(queries []*auth.UserMembershipSearchQuery) []*usr_model.UserMembershipSearchQuery {
converted := make([]*usr_model.UserMembershipSearchQuery, len(queries))
for i, q := range queries {
converted[i] = userMembershipSearchQueryToModel(q)
}
return converted
}
func userMembershipSearchQueryToModel(query *auth.UserMembershipSearchQuery) *usr_model.UserMembershipSearchQuery {
return &usr_model.UserMembershipSearchQuery{
Key: userMembershipSearchKeyToModel(query.Key),
Method: searchMethodToModel(query.Method),
Value: query.Value,
}
}
func userMembershipSearchKeyToModel(key auth.UserMembershipSearchKey) usr_model.UserMembershipSearchKey {
switch key {
case auth.UserMembershipSearchKey_USERMEMBERSHIPSEARCHKEY_TYPE:
return usr_model.UserMembershipSearchKeyMemberType
case auth.UserMembershipSearchKey_USERMEMBERSHIPSEARCHKEY_OBJECT_ID:
return usr_model.UserMembershipSearchKeyObjectID
default:
return usr_model.UserMembershipSearchKeyUnspecified
}
}
func memberTypeFromModel(memberType usr_model.MemberType) auth.MemberType {
switch memberType {
case usr_model.MemberTypeOrganisation:
return auth.MemberType_MEMBERTYPE_ORGANISATION
case usr_model.MemberTypeProject:
return auth.MemberType_MEMBERTYPE_PROJECT
case usr_model.MemberTypeProjectGrant:
return auth.MemberType_MEMBERTYPE_PROJECT_GRANT
default:
return auth.MemberType_MEMBERTYPE_UNSPECIFIED
}
}

View File

@@ -3,7 +3,7 @@ package auth
import ( import (
"github.com/caos/logging" "github.com/caos/logging"
usr_model "github.com/caos/zitadel/internal/user/model" usr_model "github.com/caos/zitadel/internal/user/model"
auth "github.com/caos/zitadel/pkg/grpc/auth" "github.com/caos/zitadel/pkg/grpc/auth"
"github.com/golang/protobuf/ptypes" "github.com/golang/protobuf/ptypes"
) )

View File

@@ -2,9 +2,10 @@ package auth
import ( import (
"github.com/caos/logging" "github.com/caos/logging"
"github.com/golang/protobuf/ptypes"
usr_model "github.com/caos/zitadel/internal/user/model" usr_model "github.com/caos/zitadel/internal/user/model"
"github.com/caos/zitadel/pkg/grpc/auth" "github.com/caos/zitadel/pkg/grpc/auth"
"github.com/golang/protobuf/ptypes"
) )
func machineViewFromModel(machine *usr_model.MachineView) *auth.MachineView { func machineViewFromModel(machine *usr_model.MachineView) *auth.MachineView {
@@ -16,36 +17,3 @@ func machineViewFromModel(machine *usr_model.MachineView) *auth.MachineView {
LastKeyAdded: lastKeyAdded, LastKeyAdded: lastKeyAdded,
} }
} }
func machineKeyViewsFromModel(keys ...*usr_model.MachineKeyView) []*auth.MachineKeyView {
keyViews := make([]*auth.MachineKeyView, len(keys))
for i, key := range keys {
keyViews[i] = machineKeyViewFromModel(key)
}
return keyViews
}
func machineKeyViewFromModel(key *usr_model.MachineKeyView) *auth.MachineKeyView {
creationDate, err := ptypes.TimestampProto(key.CreationDate)
logging.Log("MANAG-gluk7").OnError(err).Debug("unable to parse timestamp")
expirationDate, err := ptypes.TimestampProto(key.CreationDate)
logging.Log("MANAG-gluk7").OnError(err).Debug("unable to parse timestamp")
return &auth.MachineKeyView{
Id: key.ID,
CreationDate: creationDate,
ExpirationDate: expirationDate,
Sequence: key.Sequence,
Type: machineKeyTypeFromModel(key.Type),
}
}
func machineKeyTypeFromModel(typ usr_model.MachineKeyType) auth.MachineKeyType {
switch typ {
case usr_model.MachineKeyTypeJSON:
return auth.MachineKeyType_MACHINEKEY_JSON
default:
return auth.MachineKeyType_MACHINEKEY_UNSPECIFIED
}
}

View File

@@ -32,6 +32,13 @@ func (s *Server) CreateOIDCApplication(ctx context.Context, in *management.OIDCA
} }
return oidcAppFromDomain(app), nil return oidcAppFromDomain(app), nil
} }
func (s *Server) CreateAPIApplication(ctx context.Context, in *management.APIApplicationCreate) (*management.Application, error) {
app, err := s.project.AddApplication(ctx, apiAppCreateToModel(in))
if err != nil {
return nil, err
}
return appFromModel(app), nil
}
func (s *Server) UpdateApplication(ctx context.Context, in *management.ApplicationUpdate) (*management.Application, error) { func (s *Server) UpdateApplication(ctx context.Context, in *management.ApplicationUpdate) (*management.Application, error) {
app, err := s.command.ChangeApplication(ctx, in.ProjectId, appUpdateToDomain(in), authz.GetCtxData(ctx).OrgID) app, err := s.command.ChangeApplication(ctx, in.ProjectId, appUpdateToDomain(in), authz.GetCtxData(ctx).OrgID)
if err != nil { if err != nil {
@@ -61,6 +68,14 @@ func (s *Server) UpdateApplicationOIDCConfig(ctx context.Context, in *management
return oidcConfigFromDomain(config), nil return oidcConfigFromDomain(config), nil
} }
func (s *Server) UpdateApplicationAPIConfig(ctx context.Context, in *management.APIConfigUpdate) (*management.APIConfig, error) {
config, err := s.project.ChangeAPIConfig(ctx, apiConfigUpdateToModel(in))
if err != nil {
return nil, err
}
return apiConfigFromModel(config), nil
}
func (s *Server) RegenerateOIDCClientSecret(ctx context.Context, in *management.ApplicationID) (*management.ClientSecret, error) { func (s *Server) RegenerateOIDCClientSecret(ctx context.Context, in *management.ApplicationID) (*management.ClientSecret, error) {
config, err := s.command.ChangeOIDCApplicationSecret(ctx, in.ProjectId, in.Id, authz.GetCtxData(ctx).ResourceOwner) config, err := s.command.ChangeOIDCApplicationSecret(ctx, in.ProjectId, in.Id, authz.GetCtxData(ctx).ResourceOwner)
if err != nil { if err != nil {
@@ -69,6 +84,14 @@ func (s *Server) RegenerateOIDCClientSecret(ctx context.Context, in *management.
return &management.ClientSecret{ClientSecret: config.ClientSecretString}, nil return &management.ClientSecret{ClientSecret: config.ClientSecretString}, nil
} }
func (s *Server) RegenerateAPIClientSecret(ctx context.Context, in *management.ApplicationID) (*management.ClientSecret, error) {
config, err := s.project.ChangeAPIConfigSecret(ctx, in.ProjectId, in.Id)
if err != nil {
return nil, err
}
return &management.ClientSecret{ClientSecret: config.ClientSecretString}, nil
}
func (s *Server) ApplicationChanges(ctx context.Context, changesRequest *management.ChangeRequest) (*management.Changes, error) { func (s *Server) ApplicationChanges(ctx context.Context, changesRequest *management.ChangeRequest) (*management.Changes, error) {
response, err := s.project.ApplicationChanges(ctx, changesRequest.Id, changesRequest.SecId, changesRequest.SequenceOffset, changesRequest.Limit, changesRequest.Asc) response, err := s.project.ApplicationChanges(ctx, changesRequest.Id, changesRequest.SecId, changesRequest.SequenceOffset, changesRequest.Limit, changesRequest.Asc)
if err != nil { if err != nil {
@@ -76,3 +99,32 @@ func (s *Server) ApplicationChanges(ctx context.Context, changesRequest *managem
} }
return appChangesToResponse(response, changesRequest.GetSequenceOffset(), changesRequest.GetLimit()), nil return appChangesToResponse(response, changesRequest.GetSequenceOffset(), changesRequest.GetLimit()), nil
} }
func (s *Server) SearchClientKeys(ctx context.Context, req *management.ClientKeySearchRequest) (*management.ClientKeySearchResponse, error) {
result, err := s.project.SearchClientKeys(ctx, clientKeySearchRequestToModel(req))
if err != nil {
return nil, err
}
return clientKeySearchResponseFromModel(result), nil
}
func (s *Server) GetClientKey(ctx context.Context, req *management.ClientKeyIDRequest) (*management.ClientKeyView, error) {
key, err := s.project.GetClientKey(ctx, req.ProjectId, req.ApplicationId, req.KeyId)
if err != nil {
return nil, err
}
return clientKeyViewFromModel(key), nil
}
func (s *Server) AddClientKey(ctx context.Context, req *management.AddClientKeyRequest) (*management.AddClientKeyResponse, error) {
key, err := s.project.AddClientKey(ctx, addClientKeyToModel(req))
if err != nil {
return nil, err
}
return addClientKeyFromModel(key), nil
}
func (s *Server) DeleteClientKey(ctx context.Context, req *management.ClientKeyIDRequest) (*empty.Empty, error) {
err := s.project.RemoveClientKey(ctx, req.ProjectId, req.ApplicationId, req.KeyId)
return &empty.Empty{}, err
}

View File

@@ -2,18 +2,20 @@ package management
import ( import (
"encoding/json" "encoding/json"
"github.com/caos/zitadel/internal/v2/domain" "time"
"google.golang.org/protobuf/types/known/timestamppb"
"github.com/caos/logging" "github.com/caos/logging"
"github.com/golang/protobuf/ptypes" "github.com/golang/protobuf/ptypes"
"google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/durationpb"
"google.golang.org/protobuf/types/known/structpb" "google.golang.org/protobuf/types/known/structpb"
"google.golang.org/protobuf/types/known/timestamppb"
"github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/eventstore/models"
key_model "github.com/caos/zitadel/internal/key/model"
"github.com/caos/zitadel/internal/model" "github.com/caos/zitadel/internal/model"
proj_model "github.com/caos/zitadel/internal/project/model" proj_model "github.com/caos/zitadel/internal/project/model"
"github.com/caos/zitadel/internal/v2/domain"
"github.com/caos/zitadel/pkg/grpc/management" "github.com/caos/zitadel/pkg/grpc/management"
"github.com/caos/zitadel/pkg/grpc/message" "github.com/caos/zitadel/pkg/grpc/message"
) )
@@ -25,6 +27,28 @@ func appFromDomain(app domain.Application) *management.Application {
Name: app.GetApplicationName(), Name: app.GetApplicationName(),
} }
} }
func appFromModel(app *proj_model.Application) *management.Application {
changeDate, err := ptypes.TimestampProto(app.ChangeDate)
logging.Log("GRPC-di7rw").OnError(err).Debug("unable to parse timestamp")
return &management.Application{
Id: app.AppID,
State: appStateFromModel(app.State),
ChangeDate: changeDate,
Name: app.Name,
Sequence: app.Sequence,
AppConfig: appConfigFromModel(app),
}
}
func appConfigFromModel(app *proj_model.Application) management.AppConfig {
if app.Type == proj_model.AppTypeAPI {
return &management.Application_ApiConfig{
ApiConfig: apiConfigFromModel(app.APIConfig),
}
}
return nil
}
func oidcAppFromDomain(app *domain.OIDCApp) *management.Application { func oidcAppFromDomain(app *domain.OIDCApp) *management.Application {
return &management.Application{ return &management.Application{
@@ -41,6 +65,7 @@ func oidcAppConfigFromDomain(app *domain.OIDCApp) management.AppConfig {
return &management.Application_OidcConfig{ return &management.Application_OidcConfig{
OidcConfig: oidcConfigFromDomain(app), OidcConfig: oidcConfigFromDomain(app),
} }
return nil
} }
func oidcConfigFromDomain(config *domain.OIDCApp) *management.OIDCConfig { func oidcConfigFromDomain(config *domain.OIDCApp) *management.OIDCConfig {
@@ -65,6 +90,14 @@ func oidcConfigFromDomain(config *domain.OIDCApp) *management.OIDCConfig {
} }
} }
func apiConfigFromModel(config *proj_model.APIConfig) *management.APIConfig {
return &management.APIConfig{
ClientId: config.ClientID,
ClientSecret: config.ClientSecretString,
AuthMethodType: apiAuthMethodTypeFromModel(config.AuthMethodType),
}
}
func oidcConfigFromApplicationViewModel(app *proj_model.ApplicationView) *management.OIDCConfig { func oidcConfigFromApplicationViewModel(app *proj_model.ApplicationView) *management.OIDCConfig {
return &management.OIDCConfig{ return &management.OIDCConfig{
RedirectUris: app.OIDCRedirectUris, RedirectUris: app.OIDCRedirectUris,
@@ -74,11 +107,11 @@ func oidcConfigFromApplicationViewModel(app *proj_model.ApplicationView) *manage
ClientId: app.OIDCClientID, ClientId: app.OIDCClientID,
AuthMethodType: oidcAuthMethodTypeFromModel(app.OIDCAuthMethodType), AuthMethodType: oidcAuthMethodTypeFromModel(app.OIDCAuthMethodType),
PostLogoutRedirectUris: app.OIDCPostLogoutRedirectUris, PostLogoutRedirectUris: app.OIDCPostLogoutRedirectUris,
Version: oidcVersionFromModel(app.OIDCVersion), Version: oidcVersionFromDomain(domain.OIDCVersion(app.OIDCVersion)),
NoneCompliant: app.NoneCompliant, NoneCompliant: app.NoneCompliant,
ComplianceProblems: complianceProblemsToLocalizedMessages(app.ComplianceProblems), ComplianceProblems: complianceProblemsToLocalizedMessages(app.ComplianceProblems),
DevMode: app.DevMode, DevMode: app.DevMode,
AccessTokenType: oidcTokenTypeFromModel(app.AccessTokenType), AccessTokenType: oidcTokenTypeFromDomain(domain.OIDCTokenType(app.AccessTokenType)),
AccessTokenRoleAssertion: app.AccessTokenRoleAssertion, AccessTokenRoleAssertion: app.AccessTokenRoleAssertion,
IdTokenRoleAssertion: app.IDTokenRoleAssertion, IdTokenRoleAssertion: app.IDTokenRoleAssertion,
IdTokenUserinfoAssertion: app.IDTokenUserinfoAssertion, IdTokenUserinfoAssertion: app.IDTokenUserinfoAssertion,
@@ -124,6 +157,29 @@ func appUpdateToDomain(app *management.ApplicationUpdate) domain.Application {
} }
} }
func apiAppCreateToModel(app *management.APIApplicationCreate) *proj_model.Application {
return &proj_model.Application{
ObjectRoot: models.ObjectRoot{
AggregateID: app.ProjectId,
},
Name: app.Name,
Type: proj_model.AppTypeAPI,
APIConfig: &proj_model.APIConfig{
AuthMethodType: apiAuthMethodTypeToModel(app.AuthMethodType),
},
}
}
func appUpdateToModel(app *management.ApplicationUpdate) *proj_model.Application {
return &proj_model.Application{
ObjectRoot: models.ObjectRoot{
AggregateID: app.ProjectId,
},
AppID: app.Id,
Name: app.Name,
}
}
func oidcConfigUpdateToDomain(app *management.OIDCConfigUpdate) *domain.OIDCApp { func oidcConfigUpdateToDomain(app *management.OIDCConfigUpdate) *domain.OIDCApp {
return &domain.OIDCApp{ return &domain.OIDCApp{
ObjectRoot: models.ObjectRoot{ ObjectRoot: models.ObjectRoot{
@@ -145,6 +201,16 @@ func oidcConfigUpdateToDomain(app *management.OIDCConfigUpdate) *domain.OIDCApp
} }
} }
func apiConfigUpdateToModel(app *management.APIConfigUpdate) *proj_model.APIConfig {
return &proj_model.APIConfig{
ObjectRoot: models.ObjectRoot{
AggregateID: app.ProjectId,
},
AppID: app.ApplicationId,
AuthMethodType: apiAuthMethodTypeToModel(app.AuthMethodType),
}
}
func applicationSearchRequestsToModel(request *management.ApplicationSearchRequest) *proj_model.ApplicationSearchRequest { func applicationSearchRequestsToModel(request *management.ApplicationSearchRequest) *proj_model.ApplicationSearchRequest {
return &proj_model.ApplicationSearchRequest{ return &proj_model.ApplicationSearchRequest{
Offset: request.Offset, Offset: request.Offset,
@@ -404,6 +470,8 @@ func oidcAuthMethodTypeToDomain(authType management.OIDCAuthMethodType) domain.O
return domain.OIDCAuthMethodTypePost return domain.OIDCAuthMethodTypePost
case management.OIDCAuthMethodType_OIDCAUTHMETHODTYPE_NONE: case management.OIDCAuthMethodType_OIDCAUTHMETHODTYPE_NONE:
return domain.OIDCAuthMethodTypeNone return domain.OIDCAuthMethodTypeNone
case management.OIDCAuthMethodType_OIDCAUTHMETHODTYPE_PRIVATE_KEY_JWT:
return domain.OIDCAuthMethodTypePrivateKeyJWT
default: default:
return domain.OIDCAuthMethodTypeBasic return domain.OIDCAuthMethodTypeBasic
} }
@@ -422,6 +490,17 @@ func oidcAuthMethodTypeFromDomain(authType domain.OIDCAuthMethodType) management
} }
} }
func apiAuthMethodTypeToModel(authType management.APIAuthMethodType) proj_model.APIAuthMethodType {
switch authType {
case management.APIAuthMethodType_APIAUTHMETHODTYPE_BASIC:
return proj_model.APIAuthMethodTypeBasic
case management.APIAuthMethodType_APIAUTHMETHODTYPE_PRIVATE_KEY_JWT:
return proj_model.APIAuthMethodTypePrivateKeyJWT
default:
return proj_model.APIAuthMethodTypeBasic
}
}
func oidcAuthMethodTypeFromModel(authType proj_model.OIDCAuthMethodType) management.OIDCAuthMethodType { func oidcAuthMethodTypeFromModel(authType proj_model.OIDCAuthMethodType) management.OIDCAuthMethodType {
switch authType { switch authType {
case proj_model.OIDCAuthMethodTypeBasic: case proj_model.OIDCAuthMethodTypeBasic:
@@ -430,6 +509,8 @@ func oidcAuthMethodTypeFromModel(authType proj_model.OIDCAuthMethodType) managem
return management.OIDCAuthMethodType_OIDCAUTHMETHODTYPE_POST return management.OIDCAuthMethodType_OIDCAUTHMETHODTYPE_POST
case proj_model.OIDCAuthMethodTypeNone: case proj_model.OIDCAuthMethodTypeNone:
return management.OIDCAuthMethodType_OIDCAUTHMETHODTYPE_NONE return management.OIDCAuthMethodType_OIDCAUTHMETHODTYPE_NONE
case proj_model.OIDCAuthMethodTypePrivateKeyJWT:
return management.OIDCAuthMethodType_OIDCAUTHMETHODTYPE_PRIVATE_KEY_JWT
default: default:
return management.OIDCAuthMethodType_OIDCAUTHMETHODTYPE_BASIC return management.OIDCAuthMethodType_OIDCAUTHMETHODTYPE_BASIC
} }
@@ -457,14 +538,14 @@ func oidcTokenTypeFromDomain(tokenType domain.OIDCTokenType) management.OIDCToke
} }
} }
func oidcTokenTypeFromModel(tokenType proj_model.OIDCTokenType) management.OIDCTokenType { func apiAuthMethodTypeFromModel(authType proj_model.APIAuthMethodType) management.APIAuthMethodType {
switch tokenType { switch authType {
case proj_model.OIDCTokenTypeBearer: case proj_model.APIAuthMethodTypeBasic:
return management.OIDCTokenType_OIDCTokenType_Bearer return management.APIAuthMethodType_APIAUTHMETHODTYPE_BASIC
case proj_model.OIDCTokenTypeJWT: case proj_model.APIAuthMethodTypePrivateKeyJWT:
return management.OIDCTokenType_OIDCTokenType_JWT return management.APIAuthMethodType_APIAUTHMETHODTYPE_PRIVATE_KEY_JWT
default: default:
return management.OIDCTokenType_OIDCTokenType_Bearer return management.APIAuthMethodType_APIAUTHMETHODTYPE_BASIC
} }
} }
@@ -477,15 +558,6 @@ func oidcVersionFromDomain(version domain.OIDCVersion) management.OIDCVersion {
} }
} }
func oidcVersionFromModel(version proj_model.OIDCVersion) management.OIDCVersion {
switch version {
case proj_model.OIDCVersionV1:
return management.OIDCVersion_OIDCV1_0
default:
return management.OIDCVersion_OIDCV1_0
}
}
func appChangesToResponse(response *proj_model.ApplicationChanges, offset uint64, limit uint64) (_ *management.Changes) { func appChangesToResponse(response *proj_model.ApplicationChanges, offset uint64, limit uint64) (_ *management.Changes) {
return &management.Changes{ return &management.Changes{
Limit: limit, Limit: limit,
@@ -515,3 +587,126 @@ func appChangesToMgtAPI(changes *proj_model.ApplicationChanges) (_ []*management
return result return result
} }
func clientKeyViewsFromModel(keys ...*key_model.AuthNKeyView) []*management.ClientKeyView {
keyViews := make([]*management.ClientKeyView, len(keys))
for i, key := range keys {
keyViews[i] = clientKeyViewFromModel(key)
}
return keyViews
}
func clientKeyViewFromModel(key *key_model.AuthNKeyView) *management.ClientKeyView {
creationDate, err := ptypes.TimestampProto(key.CreationDate)
logging.Log("MANAG-DAs2t").OnError(err).Debug("unable to parse timestamp")
expirationDate, err := ptypes.TimestampProto(key.ExpirationDate)
logging.Log("MANAG-BDgh4").OnError(err).Debug("unable to parse timestamp")
return &management.ClientKeyView{
Id: key.ID,
CreationDate: creationDate,
ExpirationDate: expirationDate,
Sequence: key.Sequence,
Type: authNKeyTypeFromModel(key.Type),
}
}
func addClientKeyToModel(key *management.AddClientKeyRequest) *proj_model.ClientKey {
expirationDate := time.Time{}
if key.ExpirationDate != nil {
var err error
expirationDate, err = ptypes.Timestamp(key.ExpirationDate)
logging.Log("MANAG-Dgt42").OnError(err).Debug("unable to parse expiration date")
}
return &proj_model.ClientKey{
ExpirationDate: expirationDate,
Type: authNKeyTypeToModel(key.Type),
ApplicationID: key.ApplicationId,
ObjectRoot: models.ObjectRoot{AggregateID: key.ProjectId},
}
}
func addClientKeyFromModel(key *proj_model.ClientKey) *management.AddClientKeyResponse {
creationDate, err := ptypes.TimestampProto(key.CreationDate)
logging.Log("MANAG-FBzz4").OnError(err).Debug("unable to parse cretaion date")
expirationDate, err := ptypes.TimestampProto(key.ExpirationDate)
logging.Log("MANAG-sag21").OnError(err).Debug("unable to parse cretaion date")
detail, err := json.Marshal(struct {
Type string `json:"type"`
KeyID string `json:"keyId"`
Key string `json:"key"`
AppID string `json:"appId"`
ClientID string `json:"clientID"`
}{
Type: "application",
KeyID: key.KeyID,
Key: string(key.PrivateKey),
AppID: key.ApplicationID,
ClientID: key.ClientID,
})
logging.Log("MANAG-adt42").OnError(err).Warn("unable to marshall key")
return &management.AddClientKeyResponse{
Id: key.KeyID,
CreationDate: creationDate,
ExpirationDate: expirationDate,
Sequence: key.Sequence,
KeyDetails: detail,
Type: authNKeyTypeFromModel(key.Type),
}
}
func authNKeyTypeToModel(typ management.AuthNKeyType) key_model.AuthNKeyType {
switch typ {
case management.AuthNKeyType_AUTHNKEY_JSON:
return key_model.AuthNKeyTypeJSON
default:
return key_model.AuthNKeyTypeNONE
}
}
func authNKeyTypeFromModel(typ key_model.AuthNKeyType) management.AuthNKeyType {
switch typ {
case key_model.AuthNKeyTypeJSON:
return management.AuthNKeyType_AUTHNKEY_JSON
default:
return management.AuthNKeyType_AUTHNKEY_UNSPECIFIED
}
}
func clientKeySearchRequestToModel(req *management.ClientKeySearchRequest) *key_model.AuthNKeySearchRequest {
return &key_model.AuthNKeySearchRequest{
Offset: req.Offset,
Limit: req.Limit,
Asc: req.Asc,
Queries: []*key_model.AuthNKeySearchQuery{
{
Key: key_model.AuthNKeyObjectType,
Method: model.SearchMethodEquals,
Value: key_model.AuthNKeyObjectTypeApplication,
}, {
Key: key_model.AuthNKeyObjectID,
Method: model.SearchMethodEquals,
Value: req.ApplicationId,
},
},
}
}
func clientKeySearchResponseFromModel(req *key_model.AuthNKeySearchResponse) *management.ClientKeySearchResponse {
viewTimestamp, err := ptypes.TimestampProto(req.Timestamp)
logging.Log("MANAG-Sk9ds").OnError(err).Debug("unable to parse cretaion date")
return &management.ClientKeySearchResponse{
Offset: req.Offset,
Limit: req.Limit,
TotalResult: req.TotalResult,
ProcessedSequence: req.Sequence,
ViewTimestamp: viewTimestamp,
Result: clientKeyViewsFromModel(req.Result...),
}
}

View File

@@ -12,6 +12,7 @@ import (
"github.com/golang/protobuf/ptypes" "github.com/golang/protobuf/ptypes"
"github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/eventstore/models"
key_model "github.com/caos/zitadel/internal/key/model"
"github.com/caos/zitadel/internal/model" "github.com/caos/zitadel/internal/model"
usr_model "github.com/caos/zitadel/internal/user/model" usr_model "github.com/caos/zitadel/internal/user/model"
"github.com/caos/zitadel/pkg/grpc/management" "github.com/caos/zitadel/pkg/grpc/management"
@@ -52,7 +53,7 @@ func machineViewFromModel(machine *usr_model.MachineView) *management.MachineVie
} }
} }
func machineKeyViewsFromModel(keys ...*usr_model.MachineKeyView) []*management.MachineKeyView { func authnKeyViewsFromModel(keys ...*key_model.AuthNKeyView) []*management.MachineKeyView {
keyViews := make([]*management.MachineKeyView, len(keys)) keyViews := make([]*management.MachineKeyView, len(keys))
for i, key := range keys { for i, key := range keys {
keyViews[i] = machineKeyViewFromModel(key) keyViews[i] = machineKeyViewFromModel(key)
@@ -60,7 +61,7 @@ func machineKeyViewsFromModel(keys ...*usr_model.MachineKeyView) []*management.M
return keyViews return keyViews
} }
func machineKeyViewFromModel(key *usr_model.MachineKeyView) *management.MachineKeyView { func machineKeyViewFromModel(key *key_model.AuthNKeyView) *management.MachineKeyView {
creationDate, err := ptypes.TimestampProto(key.CreationDate) creationDate, err := ptypes.TimestampProto(key.CreationDate)
logging.Log("MANAG-gluk7").OnError(err).Debug("unable to parse timestamp") logging.Log("MANAG-gluk7").OnError(err).Debug("unable to parse timestamp")
@@ -133,23 +134,27 @@ func machineKeyTypeFromDomain(typ domain.MachineKeyType) management.MachineKeyTy
} }
} }
func machineKeyTypeFromModel(typ usr_model.MachineKeyType) management.MachineKeyType { func machineKeyTypeFromModel(typ key_model.AuthNKeyType) management.MachineKeyType {
switch typ { switch typ {
case usr_model.MachineKeyTypeJSON: case key_model.AuthNKeyTypeJSON:
return management.MachineKeyType_MACHINEKEY_JSON return management.MachineKeyType_MACHINEKEY_JSON
default: default:
return management.MachineKeyType_MACHINEKEY_UNSPECIFIED return management.MachineKeyType_MACHINEKEY_UNSPECIFIED
} }
} }
func machineKeySearchRequestToModel(req *management.MachineKeySearchRequest) *usr_model.MachineKeySearchRequest { func machineKeySearchRequestToModel(req *management.MachineKeySearchRequest) *key_model.AuthNKeySearchRequest {
return &usr_model.MachineKeySearchRequest{ return &key_model.AuthNKeySearchRequest{
Offset: req.Offset, Offset: req.Offset,
Limit: req.Limit, Limit: req.Limit,
Asc: req.Asc, Asc: req.Asc,
Queries: []*usr_model.MachineKeySearchQuery{ Queries: []*key_model.AuthNKeySearchQuery{
{ {
Key: usr_model.MachineKeyKeyUserID, Key: key_model.AuthNKeyObjectType,
Method: model.SearchMethodEquals,
Value: key_model.AuthNKeyObjectTypeUser,
}, {
Key: key_model.AuthNKeyObjectID,
Method: model.SearchMethodEquals, Method: model.SearchMethodEquals,
Value: req.UserId, Value: req.UserId,
}, },
@@ -157,7 +162,7 @@ func machineKeySearchRequestToModel(req *management.MachineKeySearchRequest) *us
} }
} }
func machineKeySearchResponseFromModel(req *usr_model.MachineKeySearchResponse) *management.MachineKeySearchResponse { func machineKeySearchResponseFromModel(req *key_model.AuthNKeySearchResponse) *management.MachineKeySearchResponse {
viewTimestamp, err := ptypes.TimestampProto(req.Timestamp) viewTimestamp, err := ptypes.TimestampProto(req.Timestamp)
logging.Log("MANAG-Sk9ds").OnError(err).Debug("unable to parse cretaion date") logging.Log("MANAG-Sk9ds").OnError(err).Debug("unable to parse cretaion date")
@@ -167,6 +172,6 @@ func machineKeySearchResponseFromModel(req *usr_model.MachineKeySearchResponse)
TotalResult: req.TotalResult, TotalResult: req.TotalResult,
ProcessedSequence: req.Sequence, ProcessedSequence: req.Sequence,
ViewTimestamp: viewTimestamp, ViewTimestamp: viewTimestamp,
Result: machineKeyViewsFromModel(req.Result...), Result: authnKeyViewsFromModel(req.Result...),
} }
} }

View File

@@ -24,9 +24,10 @@ type verifierMock struct{}
func (v *verifierMock) VerifyAccessToken(ctx context.Context, token, clientID string) (string, string, string, string, error) { func (v *verifierMock) VerifyAccessToken(ctx context.Context, token, clientID string) (string, string, string, string, error) {
return "", "", "", "", nil return "", "", "", "", nil
} }
func (v *verifierMock) ResolveGrants(ctx context.Context) (*authz.Grant, error) { func (v *verifierMock) SearchMyMemberships(ctx context.Context) ([]*authz.Membership, error) {
return nil, nil return nil, nil
} }
func (v *verifierMock) ProjectIDAndOriginsByClientID(ctx context.Context, clientID string) (string, []string, error) { func (v *verifierMock) ProjectIDAndOriginsByClientID(ctx context.Context, clientID string) (string, []string, error) {
return "", nil, nil return "", nil, nil
} }

View File

@@ -12,6 +12,7 @@ import (
"github.com/caos/zitadel/internal/api/authz" "github.com/caos/zitadel/internal/api/authz"
"github.com/caos/zitadel/internal/api/http" "github.com/caos/zitadel/internal/api/http"
"github.com/caos/zitadel/internal/auth_request/model" "github.com/caos/zitadel/internal/auth_request/model"
authreq_model "github.com/caos/zitadel/internal/auth_request/model"
"github.com/caos/zitadel/internal/crypto" "github.com/caos/zitadel/internal/crypto"
"github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/errors"
proj_model "github.com/caos/zitadel/internal/project/model" proj_model "github.com/caos/zitadel/internal/project/model"
@@ -55,13 +56,17 @@ func (o *OPStorage) GetClientByClientID(ctx context.Context, id string) (_ op.Cl
} }
func (o *OPStorage) GetKeyByIDAndUserID(ctx context.Context, keyID, userID string) (_ *jose.JSONWebKey, err error) { func (o *OPStorage) GetKeyByIDAndUserID(ctx context.Context, keyID, userID string) (_ *jose.JSONWebKey, err error) {
return o.GetKeyByIDAndIssuer(ctx, keyID, userID)
}
func (o *OPStorage) GetKeyByIDAndIssuer(ctx context.Context, keyID, issuer string) (_ *jose.JSONWebKey, err error) {
ctx, span := tracing.NewSpan(ctx) ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }() defer func() { span.EndWithError(err) }()
key, err := o.repo.MachineKeyByID(ctx, keyID) key, err := o.repo.MachineKeyByID(ctx, keyID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if key.UserID != userID { if key.AuthIdentifier != issuer {
return nil, errors.ThrowPermissionDenied(nil, "OIDC-24jm3", "key from different user") return nil, errors.ThrowPermissionDenied(nil, "OIDC-24jm3", "key from different user")
} }
publicKey, err := crypto.BytesToPublicKey(key.PublicKey) publicKey, err := crypto.BytesToPublicKey(key.PublicKey)
@@ -75,6 +80,29 @@ func (o *OPStorage) GetKeyByIDAndUserID(ctx context.Context, keyID, userID strin
}, nil }, nil
} }
func (o *OPStorage) ValidateJWTProfileScopes(ctx context.Context, subject string, scopes oidc.Scopes) (oidc.Scopes, error) {
user, err := o.repo.UserByID(ctx, subject)
if err != nil {
return nil, err
}
for i := len(scopes) - 1; i >= 0; i-- {
scope := scopes[i]
if strings.HasPrefix(scope, authreq_model.OrgDomainPrimaryScope) {
var orgID string
org, err := o.repo.OrgByPrimaryDomain(strings.TrimPrefix(scope, authreq_model.OrgDomainPrimaryScope))
if err == nil {
orgID = org.ID
}
if orgID != user.ResourceOwner {
scopes[i] = scopes[len(scopes)-1]
scopes[len(scopes)-1] = ""
scopes = scopes[:len(scopes)-1]
}
}
}
return scopes, nil
}
func (o *OPStorage) AuthorizeClientIDSecret(ctx context.Context, id string, secret string) (err error) { func (o *OPStorage) AuthorizeClientIDSecret(ctx context.Context, id string, secret string) (err error) {
ctx, span := tracing.NewSpan(ctx) ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }() defer func() { span.EndWithError(err) }()
@@ -85,33 +113,32 @@ func (o *OPStorage) AuthorizeClientIDSecret(ctx context.Context, id string, secr
return o.repo.AuthorizeOIDCApplication(ctx, id, secret) return o.repo.AuthorizeOIDCApplication(ctx, id, secret)
} }
func (o *OPStorage) GetUserinfoFromToken(ctx context.Context, tokenID, subject, origin string) (_ oidc.UserInfo, err error) { func (o *OPStorage) SetUserinfoFromToken(ctx context.Context, userInfo oidc.UserInfoSetter, tokenID, subject, origin string) (err error) {
ctx, span := tracing.NewSpan(ctx) ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }() defer func() { span.EndWithError(err) }()
token, err := o.repo.TokenByID(ctx, subject, tokenID) token, err := o.repo.TokenByID(ctx, subject, tokenID)
if err != nil { if err != nil {
return nil, errors.ThrowPermissionDenied(nil, "OIDC-Dsfb2", "token is not valid or has expired") return errors.ThrowPermissionDenied(nil, "OIDC-Dsfb2", "token is not valid or has expired")
} }
if token.ApplicationID != "" { if token.ApplicationID != "" {
app, err := o.repo.ApplicationByClientID(ctx, token.ApplicationID) app, err := o.repo.ApplicationByClientID(ctx, token.ApplicationID)
if err != nil { if err != nil {
return nil, err return err
} }
if origin != "" && !http.IsOriginAllowed(app.OriginAllowList, origin) { if origin != "" && !http.IsOriginAllowed(app.OriginAllowList, origin) {
return nil, errors.ThrowPermissionDenied(nil, "OIDC-da1f3", "origin is not allowed") return errors.ThrowPermissionDenied(nil, "OIDC-da1f3", "origin is not allowed")
} }
} }
return o.GetUserinfoFromScopes(ctx, token.UserID, token.ApplicationID, token.Scopes) return o.SetUserinfoFromScopes(ctx, userInfo, token.UserID, token.ApplicationID, token.Scopes)
} }
func (o *OPStorage) GetUserinfoFromScopes(ctx context.Context, userID, applicationID string, scopes []string) (_ oidc.UserInfo, err error) { func (o *OPStorage) SetUserinfoFromScopes(ctx context.Context, userInfo oidc.UserInfoSetter, userID, applicationID string, scopes []string) (err error) {
ctx, span := tracing.NewSpan(ctx) ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }() defer func() { span.EndWithError(err) }()
user, err := o.repo.UserByID(ctx, userID) user, err := o.repo.UserByID(ctx, userID)
if err != nil { if err != nil {
return nil, err return err
} }
userInfo := oidc.NewUserInfo()
roles := make([]string, 0) roles := make([]string, 0)
for _, scope := range scopes { for _, scope := range scopes {
switch scope { switch scope {
@@ -160,17 +187,40 @@ func (o *OPStorage) GetUserinfoFromScopes(ctx context.Context, userID, applicati
} }
if len(roles) == 0 || applicationID == "" { if len(roles) == 0 || applicationID == "" {
return userInfo, nil return nil
} }
projectRoles, err := o.assertRoles(ctx, userID, applicationID, roles) projectRoles, err := o.assertRoles(ctx, userID, applicationID, roles)
if err != nil { if err != nil {
return nil, err return err
} }
if len(projectRoles) > 0 { if len(projectRoles) > 0 {
userInfo.AppendClaims(ClaimProjectRoles, projectRoles) userInfo.AppendClaims(ClaimProjectRoles, projectRoles)
} }
return userInfo, nil return nil
}
func (o *OPStorage) SetIntrospectionFromToken(ctx context.Context, introspection oidc.IntrospectionResponse, tokenID, subject, clientID string) error {
token, err := o.repo.TokenByID(ctx, subject, tokenID)
if err != nil {
return errors.ThrowPermissionDenied(nil, "OIDC-Dsfb2", "token is not valid or has expired")
}
app, err := o.repo.ApplicationByClientID(ctx, clientID)
if err != nil {
return errors.ThrowPermissionDenied(nil, "OIDC-Adfg5", "client not found")
}
for _, aud := range token.Audience {
if aud == clientID || aud == app.ProjectID {
err := o.SetUserinfoFromScopes(ctx, introspection, token.UserID, clientID, token.Scopes)
if err != nil {
return err
}
introspection.SetScopes(token.Scopes)
introspection.SetClientID(token.ApplicationID)
return nil
}
}
return errors.ThrowPermissionDenied(nil, "OIDC-sdg3G", "token is not valid for this client")
} }
func (o *OPStorage) GetPrivateClaimsFromScopes(ctx context.Context, userID, clientID string, scopes []string) (claims map[string]interface{}, err error) { func (o *OPStorage) GetPrivateClaimsFromScopes(ctx context.Context, userID, clientID string, scopes []string) (claims map[string]interface{}, err error) {

View File

@@ -1,13 +1,13 @@
package oidc package oidc
import ( import (
authreq_model "github.com/caos/zitadel/internal/auth_request/model"
"strings" "strings"
"time" "time"
"github.com/caos/oidc/pkg/oidc" "github.com/caos/oidc/pkg/oidc"
"github.com/caos/oidc/pkg/op" "github.com/caos/oidc/pkg/op"
authreq_model "github.com/caos/zitadel/internal/auth_request/model"
"github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/project/model" "github.com/caos/zitadel/internal/project/model"
) )
@@ -37,7 +37,7 @@ func (c *Client) ApplicationType() op.ApplicationType {
return op.ApplicationType(c.OIDCApplicationType) return op.ApplicationType(c.OIDCApplicationType)
} }
func (c *Client) AuthMethod() op.AuthMethod { func (c *Client) AuthMethod() oidc.AuthMethod {
return authMethodToOIDC(c.OIDCAuthMethodType) return authMethodToOIDC(c.OIDCAuthMethodType)
} }
@@ -129,16 +129,18 @@ func accessTokenTypeToOIDC(tokenType model.OIDCTokenType) op.AccessTokenType {
} }
} }
func authMethodToOIDC(authType model.OIDCAuthMethodType) op.AuthMethod { func authMethodToOIDC(authType model.OIDCAuthMethodType) oidc.AuthMethod {
switch authType { switch authType {
case model.OIDCAuthMethodTypeBasic: case model.OIDCAuthMethodTypeBasic:
return op.AuthMethodBasic return oidc.AuthMethodBasic
case model.OIDCAuthMethodTypePost: case model.OIDCAuthMethodTypePost:
return op.AuthMethodPost return oidc.AuthMethodPost
case model.OIDCAuthMethodTypeNone: case model.OIDCAuthMethodTypeNone:
return op.AuthMethodNone return oidc.AuthMethodNone
case model.OIDCAuthMethodTypePrivateKeyJWT:
return oidc.AuthMethodPrivateKeyJWT
default: default:
return op.AuthMethodBasic return oidc.AuthMethodBasic
} }
} }

View File

@@ -2,9 +2,6 @@ package oidc
import ( import (
"context" "context"
"github.com/caos/zitadel/internal/telemetry/metrics"
"github.com/caos/zitadel/internal/v2/command"
"github.com/caos/zitadel/internal/v2/query"
"time" "time"
"github.com/caos/logging" "github.com/caos/logging"
@@ -15,7 +12,10 @@ import (
"github.com/caos/zitadel/internal/auth/repository" "github.com/caos/zitadel/internal/auth/repository"
"github.com/caos/zitadel/internal/config/types" "github.com/caos/zitadel/internal/config/types"
"github.com/caos/zitadel/internal/id" "github.com/caos/zitadel/internal/id"
"github.com/caos/zitadel/internal/telemetry/metrics"
"github.com/caos/zitadel/internal/telemetry/tracing" "github.com/caos/zitadel/internal/telemetry/tracing"
"github.com/caos/zitadel/internal/v2/command"
"github.com/caos/zitadel/internal/v2/query"
) )
type OPHandlerConfig struct { type OPHandlerConfig struct {
@@ -34,11 +34,12 @@ type StorageConfig struct {
} }
type EndpointConfig struct { type EndpointConfig struct {
Auth *Endpoint Auth *Endpoint
Token *Endpoint Token *Endpoint
Userinfo *Endpoint Introspection *Endpoint
EndSession *Endpoint Userinfo *Endpoint
Keys *Endpoint EndSession *Endpoint
Keys *Endpoint
} }
type Endpoint struct { type Endpoint struct {
@@ -74,6 +75,7 @@ func NewProvider(ctx context.Context, config OPHandlerConfig, command *command.C
), ),
op.WithCustomAuthEndpoint(op.NewEndpointWithURL(config.Endpoints.Auth.Path, config.Endpoints.Auth.URL)), op.WithCustomAuthEndpoint(op.NewEndpointWithURL(config.Endpoints.Auth.Path, config.Endpoints.Auth.URL)),
op.WithCustomTokenEndpoint(op.NewEndpointWithURL(config.Endpoints.Token.Path, config.Endpoints.Token.URL)), op.WithCustomTokenEndpoint(op.NewEndpointWithURL(config.Endpoints.Token.Path, config.Endpoints.Token.URL)),
op.WithCustomIntrospectionEndpoint(op.NewEndpointWithURL(config.Endpoints.Introspection.Path, config.Endpoints.Introspection.URL)),
op.WithCustomUserinfoEndpoint(op.NewEndpointWithURL(config.Endpoints.Userinfo.Path, config.Endpoints.Userinfo.URL)), op.WithCustomUserinfoEndpoint(op.NewEndpointWithURL(config.Endpoints.Userinfo.Path, config.Endpoints.Userinfo.URL)),
op.WithCustomEndSessionEndpoint(op.NewEndpointWithURL(config.Endpoints.EndSession.Path, config.Endpoints.EndSession.URL)), op.WithCustomEndSessionEndpoint(op.NewEndpointWithURL(config.Endpoints.EndSession.Path, config.Endpoints.EndSession.URL)),
op.WithCustomKeysEndpoint(op.NewEndpointWithURL(config.Endpoints.Keys.Path, config.Endpoints.Keys.URL)), op.WithCustomKeysEndpoint(op.NewEndpointWithURL(config.Endpoints.Keys.Path, config.Endpoints.Keys.URL)),

View File

@@ -4,6 +4,7 @@ import (
"context" "context"
"github.com/caos/logging" "github.com/caos/logging"
"github.com/caos/zitadel/internal/api/authz" "github.com/caos/zitadel/internal/api/authz"
"github.com/caos/zitadel/internal/config/systemdefaults" "github.com/caos/zitadel/internal/config/systemdefaults"
"github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/errors"
@@ -52,6 +53,14 @@ func (repo *OrgRepository) SearchOrgs(ctx context.Context, request *org_model.Or
return result, nil return result, nil
} }
func (repo *OrgRepository) OrgByPrimaryDomain(primaryDomain string) (*org_model.OrgView, error) {
org, err := repo.View.OrgByPrimaryDomain(primaryDomain)
if err != nil {
return nil, err
}
return model.OrgToModel(org), nil
}
func (repo *OrgRepository) GetDefaultOrgIAMPolicy(ctx context.Context) (*iam_model.OrgIAMPolicyView, error) { func (repo *OrgRepository) GetDefaultOrgIAMPolicy(ctx context.Context) (*iam_model.OrgIAMPolicyView, error) {
orgPolicy, err := repo.View.OrgIAMPolicyByAggregateID(repo.SystemDefaults.IamID) orgPolicy, err := repo.View.OrgIAMPolicyByAggregateID(repo.SystemDefaults.IamID)
if err != nil { if err != nil {

View File

@@ -2,20 +2,23 @@ package eventstore
import ( import (
"context" "context"
"time"
"github.com/caos/logging" "github.com/caos/logging"
"github.com/caos/zitadel/internal/auth/repository/eventsourcing/view"
"github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/errors"
proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing"
"github.com/caos/zitadel/internal/telemetry/tracing" "github.com/caos/zitadel/internal/telemetry/tracing"
usr_model "github.com/caos/zitadel/internal/user/model" usr_model "github.com/caos/zitadel/internal/user/model"
user_event "github.com/caos/zitadel/internal/user/repository/eventsourcing" user_event "github.com/caos/zitadel/internal/user/repository/eventsourcing"
"github.com/caos/zitadel/internal/user/repository/view/model" "github.com/caos/zitadel/internal/user/repository/view/model"
"time"
"github.com/caos/zitadel/internal/auth/repository/eventsourcing/view"
) )
type TokenRepo struct { type TokenRepo struct {
UserEvents *user_event.UserEventstore UserEvents *user_event.UserEventstore
View *view.View ProjectEvents *proj_event.ProjectEventstore
View *view.View
} }
func (repo *TokenRepo) IsTokenValid(ctx context.Context, userID, tokenID string) (bool, error) { func (repo *TokenRepo) IsTokenValid(ctx context.Context, userID, tokenID string) (bool, error) {

Some files were not shown because too many files have changed in this diff Show More